DRF: Advanced serializer usage — Dynamically modifying fields
This 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.
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 andMany-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 request
of 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