Innovate anywhere, anytime withruncode.io Your cloud-based dev studio.
Django REST Framework

How to Develop RESTful Webservice in Django using Django REST Framework

2022-07-17

DjangoRestFramework is widely used to develop restful API. Django REST Framework is easy to use who are familiar with Django, as it is developed on the core concepts of Django. In the current blog post we’ll learn how to develop a RESTful API that performs CRUD operations on the DB. 

Install Django REST famework using pip command and keep ‘rest_framework’ in your INSTALLED_APPS.
Install:

pip install djangorestframework

In settings.py

INSTALLED_APPS = (
    ...
    'rest_framework',
)

Now lets create an application with name api and create a model called ‘Country’ on which we will perform our CRUD operations.

In api/models.py

from django.db import models

class Country(models.Model):
    name = models.CharField(max_length=10)

Add api to your INSTALLED_APPS. 

INSTALLED_APPS = (
    ...
    'rest_framework',
    ‘api’,
)

Create migrations with makemigrations and migrate command which creates the tables in your DB.

python manage.py makemigrations
python manage.py migrate

One of the important part of the djangorestframework is the serializers. Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types like model instances, after first validating the incoming data. In the current blogpost we’ll deal with JSON which is the default return type.
Create serializers.py parallel to your models.py
In serializers.py

from rest_framework import serializers
from .models import *

class CountrySerializer(serializers.Serializer):
    name = serializers.CharField(max_length=250)

If you have knowledge of Django, Serializer almost serve as Form. So we included name in the field with which we do validations of name filed in the Country model.

CRUD operations:

C- Create:

We will write a view to perform create operation. We can write views in 2 ways in the same way we do in Django.

  1. Function based views.
  2. Class based View.

In the current blog we’ll go with function based views.

In views.py:

from api.serializers import *
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import *
from rest_framework import status

@api_view(['POST'])
def add_county(request):
    country_serializer = CountrySerializer(data=request.data)
    if country_serializer.is_valid():
        country_serializer.save()
        return Response({"data": "Country added successfully"}, status=status.HTTP_201_CREATED)
    else:
        error_details = []
        for key in country_serializer.errors.keys():
            error_details.append({"field": key, "message": country_serializer.errors[key][0]})

        data = {
                "Error": {
                    "status": 400,
                    "message": "Your submitted data was not valid - please correct the below errors",
                    "error_details": error_details
                    }
                }

        return Response(data, status=status.HTTP_400_BAD_REQUEST)

In serializers.py:

from rest_framework import serializers
from .models import *

class CountrySerializer(serializers.Serializer):
    name = serializers.CharField(max_length=250)

    def create(self, validated_data):
        country_obj = Country(**validated_data)
        country_obj.save()
        return country_obj

    def update(self, instance, validated_data):
        instance.name = validated_data["name"]
        instance.save()
        return instance

In urls.py:

from django.conf.urls import url
from api import views

urlpatterns = [
    url(r'^api/country/add/$', views.add_county),
]

Here in the views the decorator api_view tells the view the request methods that will allow. In the above example it is having POST so the view will allow only POST method, if we try to access the url with other request methods like GET or DELETE it will simply raise 405 Method Not Allowed exception

Similar to save of Django forms, serializers have create() and update() methods. When we call serializer.save() it will either calls create() or update() method based on the instance. 

Note: the create() or update() methods must return instance or it will raise exception.

Another important part of the webservice returning data with status code. Djangorestframework has status module that has few status codes. In our current example we would be using HTTP_200_OK(for Update, Delete and Read ), HTTP_201_CREATED(when object gets created), HTTP_400_BAD_REQUEST(for Insufficient data)).

So when user sends a request with some post data we’ll validate it with searilizers, if the given data is valid we’ld create the object by calling 

country_serializer.save()

Here the country_serializer will deserialize the data and convert to Country model object.
And return response with  HTTP_201_CREATED status code. Or return errors with HTTP_400_BAD_REQUEST if the data is insufficient.

R- Read, U- Update & D- Delete:

We’ll try to achieve the read and update operations with same view.

In views.py:

@api_view(['GET', 'POST'])
def update_county(request, id):
    country_obj = Country.objects.get(id=id)

    if request.method == "GET":
        country_data = CountrySerializer(country_obj).data
        return Response({"data": country_data}, status=status.HTTP_200_OK)
    elif request.method == "DELETE":
        country_obj.delete()
        return Response({"data": “Country Deleted Successfully.”}, status=status.HTTP_200_OK)
    else:
        country_serializer = CountrySerializer(country_obj, data=request.data)
        if country_serializer.is_valid():
            country_serializer.save()
            return Response({"data": "Country Updated successfully"}, status=status.HTTP_200_OK)
        else:
            error_details = []
            for key in country_serializer.errors.keys():
                error_details.append({"field": key, "message": country_serializer.errors[key][0]})
            data = {
                    "Error": {
                        "status": 400,
                        "message": "Your submitted data was not valid - please correct the below errors",
                        "error_details": error_details
                        }
                    }

            return Response(data, status=status.HTTP_400_BAD_REQUEST)

In urls.py:

urlpatterns = [
    url(r'^api/country/add/$', views.add_county),
    url(r'^api/country/(?P<id>[^/]*)/$', views.update_county),
]

Here in the Read and Update we’ll see the actual use of serializers, that is serializing and deserializing. While reading the serializer will convert the country object to json data with 

CountrySerializer(country_obj).data

And when updating, we’ll post the data to the view, and we’ll validate in the same way we are doing in the create view. As we are passing the instance to the serializer by default it will call the update() method of serializer.

And similarly when the request method is delete we write the business logic of delete and return HTTP_200_OK status code.

In addition to CRUD, if you want to list all the country details simply return the following data.

country_data = CountrySerializer(country_queryset, many=True).data

As we are sending queryset rather than model instance we'd be passing many=True parameter to return an array.

The returning data would be:

[{‘name’:’India’, ’name’:’Japan’,....}]