Create REST API using Django REST Framework: A Comprehensive Guide

SpyroAI Avatar

Introduction

Representational State Transfer (REST) is an architectural style that allows communication between client and server over HTTP protocol. REST APIs have become increasingly popular due to their scalability and flexibility. Django, a Python web framework, offers an easy and efficient way to build REST APIs through Django REST Framework (DRF).

In this article, we will guide you through the process of creating a REST API using Django REST Framework. You will learn how to set up a project, define serializers and views, create models, migrate database, and test endpoints. By the end of this tutorial, you will have a basic understanding of how to build REST APIs using Django REST Framework.

Prerequisites

Before we dive into building our REST API using Django REST Framework, there are a few prerequisites that you should have:

  • Python 3.x installed on your system
  • Django 3.x installed on your system
  • Basic understanding of Python programming language
  • Basic understanding of HTTP protocol

On Mac or Linux

. myenv/bin/activate 

On Window

myenv\\scripts\\activate 

Now, install django via the pip command

pip install django  

We are ready to create Django Project and app.

We have created a project and app; it must be registered in the settings.py file. Also, add rest_framework in the list of applications to let Django know we will be using Django REST Framework.

INSTALLED_APPS = [
\’django.contrib.admin\’,
\’django.contrib.auth\’,
\’django.contrib.contenttypes\’,
\’django.contrib.sessions\’,
\’django.contrib.messages\’,
\’django.contrib.staticfiles\’,
\’rest_framework\’,
\’sample_api\’,
]

Once we register the application, we can migrate (initialize the database) and create a superuser to keep track the database.

python manage.py migrate

python manage.py createsuperuser

Now, enter the required details and create the superuser. We are ready to start the server that can accept requests.

python manage.py runserver 

Creating a REST API in Django Using DRF

from django.db import models

class Students(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
address = models.CharField(max_length=200)
roll_number = models.IntegerField()
mobile = models.CharField(max_length=10)

def __str__(self):  
    return self.first_name + \" \" + self.last_name  

We created our model and we will register this model with Django. To visible this into the admin panel, we will add the following line in the sample_app/admin.py.

from django.contrib import admin
from .models import Students

admin.site.register(Students)

Our new model is registered. We will need to makemigration to reflect the Student table into the database. Run the following commands in the terminal.

python3 manage.py makemigrations 

python3 manage.py migrate  

What are serializers?

Serializers in Django REST Framework (DRF) are classes that allow complex data types, such as Django models, to be converted into JSON, XML, or other content types that can be transferred over the internet. In other words, serializers convert Python objects into a format that can be easily transferred over the network.

DRF provides two types of serializers: ModelSerializer and Serializer. ModelSerializer is a shortcut that automatically generates a serializer based on the model fields. Serializer is a more flexible option that allows you to define the serializer fields manually.

from rest_framework import serializers
from .models import Students

class StudentSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(max_length=200, required=True)
last_name = serializers.CharField(max_length=200, required=True)
address = serializers.CharField(max_length=200, required=True)
roll_number = serializers.IntegerField()
mobile = serializers.CharField(max_length=10, required=True)

class Meta:  
    model = Students  
    fields = (\'__all__\')  

We have used the Modelserializer class, the same as the ModelForm class in Django. The serializers can also be created using the Serializers class.

from rest_framework import serializers
from .models import Students

class StudentSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(max_length=200, required=True)
last_name = serializers.CharField(max_length=200, required=True)
address = serializers.CharField(max_length=200, required=True)
roll_number = serializers.IntegerField()
mobile = serializers.CharField(max_length=10, required=True)

def create(self, validated_data):  
    \"\"\" 
    Create and return a new `Students` instance, given the validated data. 
    \"\"\"  
    return Students.objects.create(**validated_data)  

def update(self, instance, validated_data):  
    \"\"\" 
    Update and return an existing `Students` instance, given the validated data. 
    \"\"\"  
    instance.first_name = validated_data.get(\'first_name\', instance.first_name)  
    instance.last_name = validated_data.get(\'last_name\', instance.last_name)  
    instance.address = validated_data.get(\'address\', instance.address)  
    instance.roll_number = validated_data.get(\'roll_number\', instance.roll_number)  
    instance.mobile = validated_data.get(\'mobile\', instance.mobile)  

    instance.save()  
    return instance  

Create Views

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Students
from .serializers import StudentSerializer

class StudentView(APIView):

def get(self, request, *args, **kwargs):  
    result = Students.objects.all()  
    serializers = StudentSerializer(result, many=True)  
    return Response({\'status\': \'success\', \"students\":serializers.data}, status=200)  

 def post(self, request):  
    serializer = StudentSerializer(data=request.data)  
    if serializer.is_valid():  
        serializer.save()  
        return Response({\"status\": \"success\", \"data\": serializer.data}, status=status.HTTP_200_OK)  
    else:  
        return Response({\"status\": \"error\", \"data\": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)

Setup Endpoints for View

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path(\’admin/\’, admin.site.urls),
path(\’api/\’, include(\’sample_app.urls\’))
]

Let\’s create the endpoints for the get() and post() method. It requires to create urls.py file in the sample_app folder. We will add the following code in the sample_app/urls.py file.

from .views import StudentView
from django.urls import path

urlpattern = [
path(\’basic/\’, StudentView.as_view())
]

Running the Runserver

python manage.py runserver  

When we visit to the local server http://127.0.0.1:8000/ it will show our endpoints where we can check our defined endpoints.

http://127.0.0.1:8000/api/basic/ the actual path to test get() and post() method. First we verify the get() method.

{
\”status\”: \”success\”,
\”students\”: [
{
\”id\”: 1,
\”first_name\”: \”Rohit\”,
\”last_name\”: \”Sharma\”,
\”address\”: \”Agra\”,
\”roll_number\”: 101,
\”mobile\”: \”1234567\”
},
{
\”id\”: 2,
\”first_name\”: \”Sachin\”,
\”last_name\”: \”Malhotra\”,
\”address\”: \”Agra\”,
\”roll_number\”: 102,
\”mobile\”: \”7672573\”
},
{
\”id\”: 3,
\”first_name\”: \”Arun\”,
\”last_name\”: \”Tiwari\”,
\”address\”: \”Jamshedpur\”,
\”roll_number\”: 103,
\”mobile\”: \”67654678\”
},
{
\”id\”: 4,
\”first_name\”: \”Tusar\”,
\”last_name\”: \”Srivastava\”,
\”address\”: \”Varanasi\”,
\”roll_number\”: 104,
\”mobile\”: \”87975890\”
}
]
}

The view processes the get() request and returns the available data to the client I the JSON format.

Let\’s test POST endpoint. The post() will take data from the users and add it into the database as a new record. The DRF generates the auto-generated browsable API.

\"\"

Here we will pass the input field that will allow us to send a POST request to the endpoint.

{
\”status\”: \”success\”,
\”data\”: {
\”id\”: 5,
\”first_name\”: \”Divya\”,
\”last_name\”: \”Saxsena\”,
\”address\”: \”Noida\”,
\”roll_number\”: 105,
\”mobile\”: \”87975812\”
}
}

The new data is added to the database, which means our POST method is working fine.

Now we fetch the data; it will show the entire result in the browser.

{
\”status\”: \”success\”,
\”students\”: [
{
\”id\”: 1,
\”first_name\”: \”Rohit\”,
\”last_name\”: \”Sharma\”,
\”address\”: \”Agra\”,
\”roll_number\”: 101,
\”mobile\”: \”1234567\”
},
{
\”id\”: 2,
\”first_name\”: \”Sachin\”,
\”last_name\”: \”Malhotra\”,
\”address\”: \”Agra\”,
\”roll_number\”: 102,
\”mobile\”: \”7672573\”
},
{
\”id\”: 3,
\”first_name\”: \”Arun\”,
\”last_name\”: \”Tiwari\”,
\”address\”: \”Jamshedpur\”,
\”roll_number\”: 103,
\”mobile\”: \”67654678\”
},
{
\”id\”: 4,
\”first_name\”: \”Tusar\”,
\”last_name\”: \”Srivastava\”,
\”address\”: \”Varanasi\”,
\”roll_number\”: 104,
\”mobile\”: \”87975890\”
},
{
\”id\”: 5,
\”first_name\”: \”Divya\”,
\”last_name\”: \”Saxsena\”,
\”address\”: \”Noida\”,
\”roll_number\”: 105,
\”mobile\”: \”87975812\”
}
]
}

Request Data Validation

Input

{

        \"first_name\": \"Divankar\",  
        \"last_name\": \"Saxsena\",  
        \"address\": \"Noida\",  
        \"roll_number\": \"105\",  
        \"mobile\": \"87975812\"  
    }  

Output:

{
\”status\”: \”error\”,
\”data\”: {
\”roll_number\”:
[
\”A valid integer is required\”
]
}
}

t throws an error, because we passed the wrong type of value for the roll_number. The automatic data validation is an excellent features of the DRF. It throws an error because we passed the wrong value type for the roll_number. If we miss out on any fields, it will show the following error.

{
\”status\”: \”error\”,
\”data\”: {
\”address\”: [
\”This field is required.\”
]
}
}

Modifying Get Request Handler

class StudentView(APIView):

def get(self, request, id):  
    result = Students.objects.get(id=id)  
    if id:  
        serializers = StudentSerializer(result)  
        return Response({\'success\': \'success\', \"students\":serializers.data}, status=200)  

    result = Students.objects.all()  
    serializers = StudentSerializer(result, many=True)  
    return Response({\'status\': \'success\', \"students\":serializers.data}, status=200)  

As we can observe, StudentSerializer(result, many=True) has returned serialized data in the JSON format a list of objects. Alternatively, we can pass the id argument through the URL – http://127.0.0.1:8000/api/basic/1/. Here we pass the 1 as id, to process the request we need to modify the urls.py. We add the path as below.

from .views import StudentView
from django.urls import path

urlpatterns = [
path(\’basic/\’, StudentView.as_view()),
path(\’basic//\’, StudentView.as_view())
]

When we hit the http://127.0.0.1:8000/api/basic/1/, it will show the following result.

{
\”success\”: \”success\”,
\”students\”: {
\”id\”: 1,
\”first_name\”: \”Rohit\”,
\”last_name\”: \”Sharma\”,
\”address\”: \”Agra\”,
\”roll_number\”: 101,
\”mobile\”: \”1234567\”
}
}

Updating Values The Patch Request Handler

Class StudentView(APIView):
def patch(self, request, id):
result = Students.objects.get(id=id)
serializer = StudentSerializer(result, data = request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({\”status\”: \”success\”, \”data\”: serializer.data})
else:
return Response({\”status\”: \”error\”, \”data\”: serializer.errors})

We changed the last_name \”Sharma\” to \”Yadav\”.

{
\”id\”: 1,
\”first_name\”: \”Rohit\”,
\”last_name\”: \”Yadav\”,
\”address\”: \”Agra\”,
\”roll_number\”: 101,
\”mobile\”: \”1234567\”
}

CRUD API Complete Code

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Students
from .serializers import StudentSerializer
from django.shortcuts import get_object_or_404

class StudentView(APIView):

def get(self, request, id):  
    result = Students.objects.get(id=id)  
    if id:  
        serializers = StudentSerializer(result)  
        return Response({\'success\': \'success\', \"students\":serializers.data}, status=200)  

    result = Students.objects.all()  
    serializers = StudentSerializer(result, many=True)  
    return Response({\'status\': \'success\', \"students\":serializers.data}, status=200)  

def post(self, request):  
    serializer = StudentSerializer(data=request.data)  
    if serializer.is_valid():  
        serializer.save()  
        return Response({\"status\": \"success\", \"data\": serializer.data}, status=status.HTTP_200_OK)  
    else:  
        return Response({\"status\": \"error\", \"data\": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)  

def patch(self, request, id):  
    result = Students.objects.get(id=id)  
    serializer = StudentSerializer(result, data = request.data, partial=True)  
    if serializer.is_valid():  
        serializer.save()  
        return Response({\"status\": \"success\", \"data\": serializer.data})  
    else:  
        return Response({\"status\": \"error\", \"data\": serializer.errors})  

def delete(self, request, id=None):  
    result = get_object_or_404(Students, id=id)  
    result.delete()  
    return Response({\"status\": \"success\", \"data\": \"Record Deleted\"})  

Conclusion

This tutorial described a detailed idea of DRF and how we can build a RESTful API in Django. In this tutorial, we created a project and added a sample_app application. We created the Student model and StudentSerializer to handle the serialization and deserialization of our model. It is a CRUD API where we have important request handlers get(), post(), patch(), and delete(). By taking an idea from this, you can create CRUD APIs for shopping site for practice purpose.