Photo by Artur Tumasjan on Unsplash

DRF: Advanced serializer usage — Dynamically modifying fields

his article is to show how we can do one of the advanced serializer usages called Dynamically modification fields. Dynamic modifying fields can make a Django rest framework API act like graphQL endpoint by retrieving only the required fields from the model, which is our primary goal for this article.

Once a serializer has been initialized, the dictionary of fields that are set on the serializer can be accessed using the .fields attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.

Modifying the fields argument explicitly helps you to do curious stuff, such as modifying the serializer field arguments at runtime instead of predefining it.

This article is just to shows how Dynamically modifying fields is done and is for advanced learners so the code does all the taking for the article. Just go through the source code to get more information.

Models.py

The example we are using to demonstrate dynamically modifying fields will have a Book model which has Publisher and Author as foreign relations and many to many relations.

Views.py

We will be using the ModelViewSet and ModelSerializer to make the API for our Book model.

The ModelViewSet class inherits from GenericAPIView and includes implementations for various actions, by mixing in the behavior of the various mixin classes.

Urls.py

In this example, we are using a DefaultRouter which adds support for automatic URL routing to Django, and provides you with a simple, quick, and consistent way of wiring your view logic to a set of URLs.

API URLs (Built with #Carbon, by @dawn_labs)

The DefaultRouter thus provides these URL routes to do the create, retrieve, update, delete (CRUD) for our Book model.

Serializers.py

This is the part where all the core stuff are and we will be using a ModelSerializer to serialize the models in our project.

The default API response will be like:

If we need only the specified fields then we need to override the serializer.
The Overriding part of the ModelSerializer :

def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
request = kwargs.get('context', {}).get('request')
str_fields = request.GET.get('fields', '') if request else None
fields = str_fields.split(',') if str_fields else None
# Instantiate the superclass normally
super(BookModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields`
# argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)

What we have done is to take the fields query param from request make it a list and then update the default serializer fields to remove the unwanted ones and just include the one we have sent along with the request, for example:

If we pass the params id and price as fields like

http://localhost:8000/api/book?fields=id,price

The API returns only the values for id and price thus making it pass only the required data, not the whole.

The only tricky part of using this implementation is that, its quite different when it comes to Dynamically modify fields for nested serializers like the Foreign keys fields and Many-to-many fields.

Nested Serializers

The Nested serializers fields can also be a dynamically modifying fields by using the SerializerMethodField . TheSerializerMethodField can be used to pass the context which contains the requestof the parent serializer, so that we can pass the fields required by us to the nested serializer.

Example:

Thus we can modify the fields with the query param having the key of the nested serializer field name for example

http://localhost:8000/api/book?authors=first_name&publisher=name

The above URL will include only the first_name from the authors and name from publisher nested serializer data.

Thus we can dynamically modify the fields for nested serializers too.

The code for all the serializer:

Thus if you need to override both the nested and the ordinary ones just include the nested field name in the fields query param and the serializer will do rest of the part.

Example:

http://localhost:8000/api/book?authors=first_name&publisher=name&fields=title,authors,publisher

The authors and the publisher needs to be in the fields list

source code: https://github.com/Joel-hanson/advanced-serializer-usage

Please provide your feedback and suggestions. Follow me to get the latest updates.

Linkedin: linkedin.com/in/joel-hanson/

Portfolio: joel-hanson.github.io/

Github: github.com/Joel-hanson

Twitter: twitter.com/Joelhanson25

Works at @impressAI