Skip to content

Instantly share code, notes, and snippets.

@robintema
Last active December 7, 2020 14:10
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save robintema/5761c3be67a0c7d78ec8 to your computer and use it in GitHub Desktop.
Save robintema/5761c3be67a0c7d78ec8 to your computer and use it in GitHub Desktop.
General Django Rest Framework model serializer
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
@arayate
Copy link

arayate commented Mar 12, 2015

Hi there, really liked your idea here. I had the same sort of problem and this fixes it easily. Thanks mate.

@arayate
Copy link

arayate commented Mar 12, 2015

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.

{
        "id": 1,
        "item": {
            "id": 2,
            "category": {
                "id": 1,
                "category_name": "Food",
                "slug": "food"
            },
            "brand": {
                "id": 1,
                "brand_name": "BBQNATION"
            },
            "title": "BBQNATION",
            "primary_image": "/media/certificate_images/certificate-primary_image-bbqnation.png",
            "pricing_structure": "Crowd Buy Sale",
            "certificate_value": "250.00",
            "sale_expiry": "2015-03-19",
            "publish_status": true,
            "active": true,
            "slug": "bbqnation-2",
            "sku": null
        },
        "quantity": 1,
        "product_type": 39
    }

@cb109
Copy link

cb109 commented Apr 13, 2017

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