Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you filter a nested serializer in Django Rest Framework?

In Django Rest Framework, how do you filter a serializer when it's nested in another serializer?

My filters are imposed in the DRF viewsets, but when you call a serializer from inside another serializer, the viewset of the nested serializer never gets called, so the nested results appear unfiltered.

I have tried adding a filter on originating viewset, but it doesn't seem to filter the nested results because the nested results get called as a separate pre-fretched query. (The nested serializer is a reverse lookup, you see.)

Is it possible to add a get_queryset() override in the nested serializer itself (moving it out of the viewset), to add the filter there? I've tried that, too, with no luck.

This is what I tried, but it doesn't even seem to get called:

class QuestionnaireSerializer(serializers.ModelSerializer):     edition = EditionSerializer(read_only=True)     company = serializers.StringRelatedField(read_only=True)      class Meta:         model = Questionnaire      def get_queryset(self):         query = super(QuestionnaireSerializer, self).get_queryset(instance)         if not self.request.user.is_staff:             query = query.filter(user=self.request.user, edition__hide=False)         return query 
like image 407
John Avatar asked Jan 27 '15 05:01

John


People also ask

How does serializer work on Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

What is nested serializer?

DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.

What is Django filter?

Django-filter is a generic, reusable application to alleviate writing some of the more mundane bits of view code. Specifically, it allows users to filter down a queryset based on a model's fields, displaying the form to let them do this.


1 Answers

You can subclass the ListSerializer and overwrite the to_representation method.

By default the to_representation method calls data.all() on the nested queryset. So you effectively need to make data = data.filter(**your_filters) before the method is called. Then you need to add your subclassed ListSerializer as the list_serializer_class on the meta of the nested serializer.

  1. subclass ListSerializer, overwriting to_representation and then calling super
  2. add subclassed ListSerializer as the meta list_serializer_class on the nested Serializer

Here is the relevant code for your sample.

class FilteredListSerializer(serializers.ListSerializer):      def to_representation(self, data):         data = data.filter(user=self.context['request'].user, edition__hide=False)         return super(FilteredListSerializer, self).to_representation(data)   class EditionSerializer(serializers.ModelSerializer):      class Meta:         list_serializer_class = FilteredListSerializer         model = Edition   class QuestionnaireSerializer(serializers.ModelSerializer):     edition = EditionSerializer(read_only=True)     company = serializers.StringRelatedField(read_only=True)      class Meta:         model = Questionnaire 
like image 158
inperspective Avatar answered Sep 26 '22 19:09

inperspective