Pass extra arguments to Serializer Class in Django Rest Framework

It's very easy with "context" arg for "ModelSerializer" constructor.

For example:

in view:

my_objects = MyModelSerializer(
    input_collection, 
    many=True, 
    context={'user_id': request.user.id}
).data

in serializers:

class MyModelSerializer(serializers.ModelSerializer):
...

    is_my_object = serializers.SerializerMethodField('_is_my_find')
...

    def _is_my_find(self, obj):
        user_id = self.context.get("user_id")
        if user_id:
            return user_id in obj.my_objects.values_list("user_id", flat=True)
        return False
...

so you can use "self.context" for getting extra params.

Reference


You could in the YourView override get_serializer_context method like that:

class YourView(GenericAPIView):

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context["customer_id"] = self.kwargs['customer_id']
        context["query_params"] = self.request.query_params
        return context

or like that:

class YourView(GenericAPIView):
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        serializer.context["customer_id"] = request.user.id
        serializer.context["query_params"] = request.query_params

        serializer.is_valid(raise_exception=True)
        ...

and anywhere in your serializer you can get it. For example in a custom method:

class YourSerializer(ModelSerializer):
    def get_alternate_name(self, obj):
        customer_id = self.context["customer_id"]
        query_params = self.context["query_params"]
        ...

To fulfill the answer of redcyb - consider using in your view the get_serializer_context method from GenericAPIView, like this:

def get_serializer_context(self):
    return {'user': self.request.user.email}

A old code I wrote, that might be helpful- done to filter nested serializer:

class MySerializer(serializers.ModelSerializer):

    field3  = serializers.SerializerMethodField('get_filtered_data')

    def get_filtered_data(self, obj):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            try:
                data = Other_model.objects.get(pk_field=obj, filter_field=param_value)
            except:
                return None
            serializer = OtherSerializer(data)
            return serializer.data
        else:
            print "Error stuff"

    class Meta:
        model = Model_name
        fields = ('filed1', 'field2', 'field3')

How to override get_serializer_class:

class ViewName(generics.ListAPIView):

    def get_serializer_class(self):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            return Serializer1
        else:
            return Serializer2

    def get_queryset(self):
       .....

Hope this helps people looking for this.


List of element if your query is a list of elements:

my_data = DataSerializers(queryset_to_investigate, 
                          many=True, context={'value_to_pass': value_passed}

in case off single data query:

my_data = DataSerializers(queryset_to_investigate, 
                          context={'value_to_pass': value_passed}

Then in the serializers:

class MySerializer(serializers.ModelSerializer):
    class Meta:
        fields = '__all__'
        model = 'Name_of_your_model'

    def on_representation(self, value):
        serialized_data = super(MySerializer, self).to_representation(value)
        value_as_passed = self.context['value_to_pass']
        # ..... do all you need ......
        return serialized_data

As you can see printing the self inside on_representation you can see: query_set: <object (x)>, context={'value_to_pass': value_passed}

This is a simpler way, and you can do this in any function of serializers having self in the parameter list.