Customizing Response of Django Rest Framework from Request
Django Rest Framework(DRF) makes it simple to create usual paginated responses for you by just using a ModelSerializer
and ModelViewSet
. For example, you can easily create a response like this:
{
"count": 23,
"next": null,
"previous": null,
"results": [
... Your favorite kitten shoes list ...
]
}
This is all good and dandy, but what if you want more fields added other than and outside of just the results
serialized by your serializer.
Mind that something similar can also be achieved by using a serializer but the serializer won’t be able to help when you want access to the request object. Consider the exhibit below:
In my professional work as a python developer, I faced a situation. The situation is a very common one when you have various filters in a search engine kind of interface using a Single Page App(SPA) model. What you basically require in such cases is a sync between the state of your frontend SPA and whatever result you have got from your API.
For example, you are on an E-commerce shopping page browsing kitten shoes and it is giving you the option to filter on color. It's a SPA so the moment you mark a checkbox it fills your page with filtered results. You filtered on the shoe color Pink. The request is taking some time, but by that time you changed your mind and decided to add Black too in the mix. Now since the response speed is currently slow this second request of Black will take some more time to appear in front of you. During this time all you will be seeing are the refreshed results from the first request of just Pink. So you are perplexed and don’t know why the black color checkbox isn’t working. Frantically clicking on it worsens your situation with more slow requests to the API.
You as a developer don’t want your user to face this kind of situation. A simple solution is to always refresh your filters from the result of the API response itself. That requires you to add the requested filter parameters in the response. Something like this:
{
"count": 23,
"next": null,
"previous": null,
"results": [
... Your favorite color kitten shoes list ...
],
"request_data": {
"color": "pink,black"
}
}
Now, whenever you receive data from the API you just refresh the data and the filters on the UI both at the same time. This keeps them in sync and your user is happy and buys black kitten shoes from you. Your user is happy, you are happy and your company profits are double happy.
How do you achieve such happy-happy happenings in DRF?
I will take the example of ModelViewSet
. You can do this in any API view where ListModelMixin
is inherited.
ModelViewSet
internally already inherits from ListModelMixin
and the GET
request essentially maps itself to the list
method of your response. So, all you need to do is override this method in your class and add extra data to the response.
So you can do something like this:
def list(self, request, *args, **kwargs):
response = super().list(request, args, kwargs)
response.data["request_data"] = request.GET
return response
Now you might need this in more than one API views you will be creating. It's a good idea to just create your own ModelViewSet
class like this:
from rest_framework import viewsets
class ModelViewSet(viewsets.ModelViewSet):
def list(self, request, *args, **kwargs):
response = super().list(request, args, kwargs)
response.data["request_data"] = request.GET
return response
Put it in a viewsets.py
file somewhere in your Django app and then use this class instead of the standard ModelViewSet
. This keeps things nice and DRY.
With this we conclude, until next time folks.