Let’s say we have an entity nexus point, i.e. many other entities that have o2m relations to the same entity. Some use cases would be implementing a Note model that relates to Users, Events, Projects etc. Adding foreign keys is fine up until one point, but, since all but one of these foreign keys will be always None, let’s implement a model where the entity is retrieved programatically.
class Note(Date): ...
entity_type = models.CharField(max_length=64) entity_id = models.IntegerField()
To get the related Note for a User, we simply filter by Note.objects.get(entity_type=User, entity_id=user.id)
, similarly for other entities.
But, when retrieving the Note from a REST API, I want the related entity properly serialized, not just the type and id fields. With Django REST Framework, this only takes a few lines. In serializers.py:
from django.apps import apps from rest_framework import serializers
class NoteSerializer(serializers.ModelSerializer): ... entity = serializers.SerializerMethodField()
def get_entity(self, obj): pk = obj.entity_id class_name = obj.entity_type model_class = apps.get_model('app', class_name) model = model_class.objects.get(pk=pk)
serializer_class = class_name + 'Serializer' # assumes the "ModelNameSerializer" is the name of the serializer class in the current file
return globals()[serializer_class](model).data
class Meta: model = Note fields = (..., 'entity', ...)
Using the SerializerMethodField and defining a function prefixed with get_
will trigger the result of that function to be represented in the entity
key of the parent NoteSerializer. Inside it, we simply retrieve our related model and serialize it using the ModelNameSerializer. This means a User will always be serialized as a User, an Event as an Event and a Project as a Project.
I’ve spent a couple of hours looking for this solution, so I hope it helps in similar use cases.