[Django]-Pass extra arguments to Serializer Class in Django Rest Framework

152đź‘Ť

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

👤redcyb

52đź‘Ť

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"]
        ...
👤M.Void

29đź‘Ť

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}
👤andilabs

14đź‘Ť

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.

👤yeaske

1đź‘Ť

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.

👤Angelo

1đź‘Ť

Getting the context kwargs passed to a serializer like;

...
self.fields['category'] = HouseCategorySerializer(read_only=True, context={"all_fields": False})
...

In your serializer, that is HouseCategorySerializer do this in one of your functions

def get_houses(self, instance):
    print(self._context.get('all_fields'))

Using self._context.get('keyword') solved my mess quickly, instead of using self.get_extra_context()

0đź‘Ť

These answers are far to complicated; If you have any sort of authentication then add this property to your serializer and call it to access the user sending the request.

class BaseSerializer(serializers.ModelSerializer):

@property
def sent_from_user(self):
    return self.context['request'].user

0đź‘Ť

you can pass the arguments as keyword arguments when you initialize the serializer in your Viewset. For example:

class OneZeroViewSet(viewsets.ModelViewSet):
     serializer_class = OneZeroSerializer

def list(self, request):
    some_argument = 'some value'
    serializer = self.get_serializer(context={'arg_name': some_argument}, many=True)
    return rest_response.Response(serializer.data)

Then, you can access the arg_name value in your serializer’s init method by using the context.

class OneZeroSerializer(serializer.ModelSerializer):
     def __init__(self, *args, **kwargs):
         argument = kwargs.pop('context', {}).get('arg_name')
         print(argument)
         super().__init__(*args, **kwargs)

class Meta:
    model = OneZero
    fields = ('id', 'location')

Leave a comment