How to pass query parameters to serializers in Django Rest Framework (DRF)

2 min read

May 13, 2022

Laptop blank

This was an issue I recently had to figure out at work and I had to piece together a bunch of Stack Overflow answers and the docks to get to my solution. I figured I would document it here in case anyone has the same issue. The workflow I specifically was going for was the following:

  • In my API call determine if I had a specific query param, lets call it show_extra_data
  • If show_extra_data exists then do something

Pretty simple, but it required updates both in my API view and the serializer itself. So first let's listen in the API call for the query param in the GET request.

    from rest_framework import viewsets
from .serializers import ExampleSerializer
from .models import ExampleModel

class ExampleSerializer(viewsets.ModelViewSet):
queryset = ExampleModel.objects.all()
serializer_class = ExampleSerializer

def get_serializer_context(self):
context = super().get_serializer_context()
context.update({"show_extra_data": self.request.query_params.get('show_extra_data', False)})
return context

Most of the view is pretty standard. The important part here is get_serializer_context(). Essentially what that function does is get the context from Django Rest Framework and then add an extra key to the dictionary called show_extra_data that will return True if show_extra_data is in our query parameters, otherwise it returns false. Now when we go to the serializer you will be able to access show_extra_data as a variable in the context of the serializer.

You could theoretically add any number of items to the context to get the desired effect. I'm keeping this example simple for demonstration purposes.

Now lets take a look at the serializer

    from rest_framework import serializers
from .models import ExampleModel

class ExampleSerializer(serializers.ModelSerializer):

class Meta:
model = ExampleModel
fields = ['field_1', 'field_2']

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

include_extra_data = self.context.get('include_extra_data', False)
if include_extra_data:
# Do what you want here

Once again a pretty simple demonstration. The example above overrides the init function but you could also override any of the create, update, etc. methods and access context in the self object. Some places I think where passing a query parameter is particularly useful:

  • Conditionally adding/removing fields to your serializer
  • In serializer methods methods filtering data a certain way based on id, slug, etc.
  • Conditionally computing a field some way based

And that's about it! Hopefully someone else finds this helpful as it took a while for me to wrap my head around how all of the methods all work together to be able to pass data to one another.