Override data property of serializer in DRF
Asked Answered
B

2

6

I am using django-rest-framework-mongoengine for a personal project. I want to be able to send extra data in list requests. I have written 2 mixins for that purpose:

UserSearializerContextMixin: Collects the list of user ids for all the instances present in the list.

class UserSerializerContextMixin(object):
    user_lookup_field = 'user_id'
    user_fields_required = ['id','full_name','image','level']
    _user_ids = []

    def update_context(self,user_id):
        if not self.context.get('user_ids'):
            self.context['user_ids'] = [user_id]
        else:
            self.context['user_ids'].append(user_id)

    def to_representation(self,instance):
        self.update_context(getattr(instance,self.user_lookup_field))
        return super(UserSerializerContextMixin,self).to_representation(instance)

UserSerializerDataMixin: Override the data property using the context prepared in to_representation part.

class UserSerializerDataMixin(object):

    @property   
    def data(self):

        ret = super(UserSerializerDataMixin, self).data
        // Override the data
        return ReturnDict(ret, serializer=self)

Then for my serializer I do something like this:

class DFSerializer(UserSerializerContextMixin,UserSerializerDataMixin,DocumentSerializer):
    //Fields and all

But somehow the code just does not enter the overridden data property. I guess logically the data property should be overridden by extending the mixin. But it does not happen here.

What could possibly be the reason and how to resolve?

Bonefish answered 25/11, 2015 at 7:33 Comment(0)
P
1

This is a super old question, but just in case somebody else stumbles upon this:

I came here because I was unhappy how drf requires a different serializer output for TemplateHTMLRenderer than it does for the other renderers. So one of the possible solutions involved overriding data property to return a dict with serializer & data instead of ReturnList containing the same serializer & data.

Anyway, the problem here is that for listing records in the ViewSet, it is not your serializer instanced directly, but a ListSerializer instead and that ListSerializer then invokes your serializer for each particular record to be serialized.

An ugly patch "fixing" this problem could be made like so:

class YourViewSet(SomeBaseViewSet):

....

def get_serializer(self, *args, **kwargs):

    res = super().get_serializer(*args, **kwargs)

    class Patch(res.__class__):

        @property
        def data(self):
            request = self.context['request']
            if isinstance(request.accepted_renderer, TemplateHTMLRenderer):
                return dict(data=super().data,
                            serializer=self.child if isinstance(self, serializers.ListSerializer) else self)
            return super().data

    res.__class__ = Patch

    return res

As of time of this writing, I'm still deciding what the best approach for solving my particular problem (TemplateHTMLRenderer requiring different serialized output) is. I'm testing overriding the renderer next, but the above does "solve" my issue for me and it also explains why code didn't behave to OP's expectations.

Pumice answered 11/7, 2018 at 7:12 Comment(2)
Thanks for pointing out the ListSerializer. That's a nasty one.Greasy
Also see source for more information.Greasy
P
0

Is an old question, but meanwhile DRF is improved so is worth to add a new way to do this.

So now the easy way (and the documented way) is to create a custom ListSerializer and then use the list_serializer_class of the Meta to let DRF use the custom serializer.

So in detail:

  1. Create the custom serializer:
class CustomListSerializer(serializers.ListSerializer):
    def data(self):
        pass
  1. define the meta of the serializer in order to use the list_serializer_class
class MyCustomSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = CustomListSerializer

doc is available here: https://www.django-rest-framework.org/api-guide/serializers/#customizing-listserializer-behavior

Pleopod answered 3/9, 2024 at 10:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.