Quick Improvement REST API with Django REST Framework

Andika Pratama
5 min readSep 16, 2022

--

DRF : Part II

In a previous article I have introduced a quick way to create a REST API using the Django Rest Framework (DRF).

Next in this article we will develop the REST API that was created in the previous article so that it becomes more fast and structured. If you want to follow this tutorial, please complete the article “Quick Build REST API with Django Rest Framework” above or you can download it on the following gihub:

Before we start, make sure you have activated the Virtual Environment (VENV) and run the DRF project with the following terminal command:

=== Linux or Mac OS === 
$ . drf_env/bin/activate
=== Windows ===
c:\>source drf_env/Scripts\activate.bat
  • running DRF project:
$ python manage.py runserver

I think there are some improvements that need to be made to the REST API that has been made. Here are some of the improvements I made to the REST API that were made in the previous article.

1. Management Data ViewSets

To simplify the process of data transactions using the REST API, we need to manage ViewSets to get the desired data, for example in the previous API we can get product data by using the following url page.

http://127.0.0.1:8000/api/product_item/

http://127.0.0.1:8000/api/product_item/

In results of the request, it can be seen that the product category only displaying the id of the category model.

In actual use we also need detailed from those categories. To fix this we need to modify the product’s serializer.py file by adding CategorySerializer to ItemSerializer.

product_api/serializers.py

With this, if a request is made on a product item it will produce a more complete request result.

Furthermore, to separate the serializer rules when inputting and retrieving data, it’s a good idea to divide the ItemSerializer into two different serializers with following named:

  • WriteItemSerializer
  • ReadItemSerializer
product_api/serializers.py

and in views.py change Viewset ItemViewSets to :

class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()

def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadItemSerializer
return WriteItemSerializer

With this, when performing the POST process, API users do not need to add data id to the request form and vice versa when performing GET processes, API users will get complete data.

This will be helpful when you want to create an API where some data fields have default values or will be automatically filled in by the system. Therefore it would be nice to separate the input and data retrieval processes on different serializers.

2. Improve Query performance

To improve the performance of the query on the API we can slightly change the way the queryset data is retrieved in the existing viewset. for example, because we take category data on product items, in ItemViewSet we can change the queryset to a more optimal form.

class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.select_related("category")

def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadItemSerializer
return WriteItemSerializer

This increase is not very significant when there is little data, but when the requested data is very large, for example more than 1000 data, a very striking difference will be seen.

Another improvement we can do is Pagination. This will help when the data request has a very large amount. The more data, the longer the process of querying data when requesting.

To overcome this, it would be better if we divide the data into different segments using Pagination, this will facilitate and speed up the data retrieval process without having to wait for all the data to be completed in the query.

to add pagination we need to add a little code in the settings.py file with the following code:

settings.py

Then the result of the request will produce a display like this:

  • count → contains the number of data in one pagination segment.
  • next → contains the next paging url, will contain null if there is no next paging.
  • previous → contains the previous paging url, will contain null if there is no previous paging.
  • results → contains data from paging

to access a particular paging you only need to add a get request to the url with the format for example:

http://127.0.0.1:8000/api/product_item?page=1http://127.0.0.1:8000/api/product_item?page=2….

3. Search Filter

The next improvement is the data search feature in the API. If you need a specific list of data in the API, this search filter will make it easier to retrieve data from the API. to implement it just need to add some code to the viewset that you want to filter. for example in ItemViewsets.

from rest_framework import viewsets, filtersclass ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.select_related("category")
filter_backends = (filters.SearchFilter,)
search_fields = ("item_name",)
def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadItemSerializer
return WriteItemSerializer

With an example get request like this:

http://127.0.0.1:8000/api/product_item?search=search_query

4. Ordering Filter

The next improvement is the sorting of API request data. with this filter we can sort the data as desired. just as an example we will add an ordering filter to ItemViewSets.

from rest_framework import viewsets, filtersclass ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.select_related("category")
filter_backends = (filters.SearchFilter, filters.OrderingFilter)
search_fields = ("item_name",)
ordering_fields = ("price", "stock")
def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadItemSerializer
return WriteItemSerializer

with the get request as follows:

Ascending = http://127.0.0.1:8000/api/product_item?ordering=price

Descending = http://127.0.0.1:8000/api/product_item?ordering=-price

In the example above, I provide two ordering accesses based on product prices and product stock. For ascending sort, use the name of the field you want to sort, while for descending, use a minus sign (-) in front of the field name.

Complete Source Code

Closing remarks

Thank you for following this tutorial to the end. Hopefully this article can help you, see you in the next article.

--

--

Andika Pratama

Fresh Graduate of Computer Science at Universitas Syiah Kuala, Software Engineer. Check my github on github.com/Andika7