Last active
December 7, 2020 14:10
-
-
Save robintema/5761c3be67a0c7d78ec8 to your computer and use it in GitHub Desktop.
General Django Rest Framework model serializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
from rest_framework import serializers | |
class GeneralModelSerializer(serializers.ModelSerializer): | |
""" General model serializer that will serialize a model object. It will return all the model fields. | |
""" | |
class Meta: | |
model = None | |
def __init__(self, instance): | |
self.Meta.model = type(instance) | |
super(GeneralModelSerializer, self).__init__(instance=instance) | |
class FeedSerializer(serializers.ModelSerializer): | |
target_object = serializers.SerializerMethodField('get_serialized_target_object') | |
SERIALIZERS = { | |
'accounts.user': MinimalUserSerializer, | |
'posts.post': MinimalPostSerializer | |
} | |
class Meta: | |
model = Action | |
fields = ('id', 'target_object', 'timestamp', 'public') | |
def get_serialized_target_object(self, obj): | |
""" Serialize a model object | |
If the object does not have special serializer class use the general one | |
""" | |
content_type, pk = obj.target_content_type, obj.target_object_id | |
if content_type and pk: | |
model_class = content_type.model_class() | |
try: | |
instance = model_class.objects.get(pk=pk) | |
except model_class.DoesNotExist: | |
return None | |
app_model = '{0}.{1}'.format(content_type.app_label,content_type.model) | |
if app_model in self.SERIALIZERS.keys(): | |
serializer = self.SERIALIZERS[app_model] | |
else: | |
logger = logging.getLogger(__name__) | |
logger.error('No secure serializer found for {0}'.format(app_model)) | |
serializer = GeneralModelSerializer | |
return serializer(instance=instance).data | |
else: | |
return None |
I had your exact same problem, trying to serialize an action that would point to a user plus one of a number of different models (however a generic serialization for those would suffice in my case). Nice approach, thanks 👍
One thing:
- Newer versions of DRF force you to specify the serializer fields explicitly, so your
GeneralModelSerializer
would need a
class Meta:
model = None
fields = "__all__"
This is my slightly simplified version of your action serializer:
class ActionSerializer(serializers.ModelSerializer):
actor = UserSerializer()
action_object = serializers.SerializerMethodField()
class Meta:
model = Action
fields = ("id", "actor", "verb", "action_object", "description",
"timestamp", "public")
def get_action_object(self, obj):
"""Use a generic serializer."""
content_type, pk = (obj.action_object_content_type,
obj.action_object_object_id)
if content_type and pk:
model_class = content_type.model_class()
try:
instance = model_class.objects.get(pk=pk)
except model_class.DoesNotExist:
return None
return GeneralModelSerializer(instance=instance).data
else:
return None
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently for one API, I am getting below response. Here, 'product_type' is content-type. It has integer value(table ID maybe). I want model name instead of table ID in below get API. Can you please help me out.