Open In App

How to return custom JSON in Django REST Framework ?

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

In this article, we will create class-based views and combine this with the serializer class to return JSON representation for each HTTP request. For our class-based views, we will make use of a set of generic views, which help to achieve minimum lines code. 

  • Generic Classes and Viewsets
  • HTTP requests to interact with relationship resources

Generic Classes and Viewsets

We will take advantage of generic class views to implement get, post, delete, put, and patch methods. For this, we need to make use of two generic class views from the rest_framework.generics module. They are:

  • ListCreateAPIView
  • RetrieveUpdateDestroyAPIView

The ListCreateAPIView class view implements the get method (retrieves a listing of a queryset) and post method (creates a model instance). And, the RetrieveUpdateDestroyAPIView class view implements get (retrieve a model instance), delete (delete a model instance), put (completely update a model instance), and patch (partially update a model instance).

In the Django REST framework, these two generic views are implemented as mixin classes. The ListCreateAPIView uses ListModelMixin and CreateModelMixin from rest_framework.mixins module and GenericAPIView from rest_framework.generics module. Let’s look at its declaration.

Python3




class ListCreateAPIView(mixins.ListModelMixin, 
                        mixins.CreateModelMixin, GenericAPIView):


The RetrieveUpdateDestroyAPIView uses RetrieveModelMixin, UpdateModelMixin and DestroyModelMixin from rest_framework.mixins module and GenericAPIView from rest_framework.generics module. Let’s look at its declaration.

Python3




class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, 
                                   mixins.UpdateModelMixin, 
                                   mixins.DestroyModelMixin, 
                                   GenericAPIView):


Now, let’s get back to our RESTFul web service code and create the required set of Django class-based views. You can open the restpi\robots\views.py Python file and replace it with the below code.

Python3




from django.shortcuts import render
  
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
  
from robots.models import RobotCategory
from robots.models import Manufacturer
from robots.models import Robot
  
from robots.serializers import RobotCategorySerializer
from robots.serializers import ManufacturerSerializer
from robots.serializers import RobotSerializer
  
class ApiRoot(generics.GenericAPIView):
    name = 'api-root'
    def get(self, request, *args, **kwargs):
        return Response({
            'robot-categories': reverse(RobotCategoryList.name, request=request),
            'manufacturers': reverse(ManufacturerList.name, request=request),
            'robots': reverse(RobotList.name, request=request)
            })            
      
class RobotCategoryList(generics.ListCreateAPIView):
    queryset = RobotCategory.objects.all()
    serializer_class = RobotCategorySerializer
      
class RobotCategoryDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = RobotCategory.objects.all()
    serializer_class = RobotCategorySerializer
    name = 'robotcategory-detail'
  
class ManufacturerList(generics.ListCreateAPIView):
    queryset = Manufacturer.objects.all()
    serializer_class = ManufacturerSerializer
    name = 'manufacturer-list'
  
class ManufacturerDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Manufacturer.objects.all()
    serializer_class = ManufacturerSerializer
    name = 'manufacturer-detail'        
  
class RobotList(generics.ListCreateAPIView):
    queryset = Robot.objects.all()
    serializer_class = RobotSerializer
    name = 'robot-list'
  
class RobotDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Robot.objects.all()
    serializer_class = RobotSerializer
    name = 'robot-detail'


Here the RobotCategoryList, ManufacturerList, and RobotList are the subclasses of generics.ListCreateAPIView; the RobotCategoryDetail, ManufacturerDetail, and RobotDetail are the subclasses of generics.RetrieveUpdateDestroyAPIView. Every subclass has a queryset attribute, serializer_class attribute, and a name attribute. The queryset attribute stores all the retrieved objects, the serializer_class attribute stores the serializer class, and the name attribute is used to identify each view.

Apart from class-based views, you can notice an ApiRoot class, which is a subclass of the rest_framework.generics.GenericAPIView

Python3




class ApiRoot(generics.GenericAPIView):
    name = 'api-root'
    def get(self, request, *args, **kwargs):
        return Response({
            'robot-categories': reverse(RobotCategoryList.name, request=request),
            'manufacturers': reverse(ManufacturerList.name, request=request),
            'robots': reverse(RobotList.name, request=request)
            })


The ApiRoot class creates an end-point for the root of our RESTful web service that facilitates browsing the resource collection. The get method defines in this class returns a Response object that has the descriptive name and its URL. Here, it returns descriptive name and URL for robot categories list, manufacturers list, and robots list. 

Next, we need to specify the URL pattern in the regular expression to run a specific method for a class-based view defined in the views.py Python file. The client HTTP request has to match with this regular expression to run the methods in the views.py file. You can create the urls.py file in the restapi/robots and add the below code.

Python3




from django.conf.urls import url
from robots import views
  
urlpatterns = [
    url(r'^robot-categories/$',
        views.RobotCategoryList.as_view(),
        name=views.RobotCategoryList.name),
    
    url(r'^robot-categories/(?P<pk>[0-9]+)$',
        views.RobotCategoryDetail.as_view(),
        name=views.RobotCategoryDetail.name),
    
    url(r'^manufacturers/$',
        views.ManufacturerList.as_view(),
        name=views.ManufacturerList.name),
      
    url(r'^manufacturers/(?P<pk>[0-9]+)$',
        views.ManufacturerDetail.as_view(),
        name=views.ManufacturerDetail.name),
    
    url(r'^robots/$',
        views.RobotList.as_view(),
        name=views.RobotList.name),
    
    url(r'^robots/(?P<pk>[0-9]+)$',
        views.RobotDetail.as_view(),
        name=views.RobotDetail.name),
    
    url(r'^$',
        views.ApiRoot.as_view(),
        name=views.ApiRoot.name),
]


As a final step, we need to define the root URL configuration. You can open the restapi/restapi/urls.py Python file and replace it with the below code:

Python3




from django.conf.urls import url, include
  
urlpatterns = [
    url(r'^', include('robots.urls')),
]


HTTP requests to interact with resources

It is time to test our code by composing and sending the various HTTP requests. Here, we will take advantage of both the HTTPie command and the CURL command.

Create a new robot category

Let’s compose and send an HTTP Post request to create a new robot category. The HTTPie command is:

http POST :8000/robot-categories/ name=”Articulated Robots” notes=”Flexibility, dexterity, and reach make articulated robots ideally suited for tasks that span non-parallel planes”

Output:

Robot Category Post Request (HTTPie)

Let’s create another robot category using the curl command. 

curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”SCARA Robots\”, \”notes\”:\”A Selective Compliance Articulated Robot Arm (SCARA) is a good and cost-effective choice for performing operations between two parallel planes\”}” localhost:8000/robot-categories/

Output:

Robot Category POST request (cURL)

Retrieve all robot categories

Let’s compose a GET request to retrieve all robot categories. The HTTPie command is:

http :8000/robot-categories/

Output:

Robot Category GET request (HTTPie utility command)

The equivalent curl command is

curl -iX GET localhost:8000/robot-categories/

Output:

GET request (cURL)

Retrieve a single robot category

The HTTPie command to retrieve a robot category is:

http :8000/robot-categories/1

Output:

GET request (single category)

The equivalent curl command is:

curl -iX GET localhost:8000/robot-categories/1

Create a new manufacturer

Let’s compose and send an HTTP POST request to create a manufacturer. The HTTPie command is:

http :8000/manufacturers/ name=”FANUC Global” rating=4 notes=”The automation specialist and industrial robot manufacturer”

Output:

HTTP/1.1 201 Created

Allow: GET, POST, HEAD, OPTIONS

Content-Length: 219

Content-Type: application/json

Date: Mon, 16 Nov 2020 06:36:12 GMT

Location: http://localhost:8000/manufacturers/1

Referrer-Policy: same-origin

Server: WSGIServer/0.2 CPython/3.7.5

Vary: Accept, Cookie

X-Content-Type-Options: nosniff

X-Frame-Options: DENY

{

    “entry_date”: “2020-11-16T06:36:12.449074Z”,

    “robots”: [],

    “name”: “FANUC Global”,

    “notes”: “The automation specialist and industrial robot manufacturer”,

    “pk”: 1,

    “rating”: 4,

    “url”: “http://localhost:8000/manufacturers/1”

}

Let’s create another manufacturer using the curl command.

curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”ABB\”, \”rating\”:5, \”notes\”:\”Focused in Electrification, Industrial Automation, Robotics, Discrete Automation and Motion\”}” localhost:8000/manufacturers/

Output:

HTTP/1.1 201 Created

Date: Mon, 16 Nov 2020 06:49:43 GMT

Server: WSGIServer/0.2 CPython/3.7.5

Content-Type: application/json

Location: http://localhost:8000/manufacturers/2

Vary: Accept, Cookie

Allow: GET, POST, HEAD, OPTIONS

X-Frame-Options: DENY

Content-Length: 242

X-Content-Type-Options: nosniff

Referrer-Policy: same-origin

{“url”:”http://localhost:8000/manufacturers/2″,”pk”:2,”name”:”ABB”,”rating”:5,

“notes”:”Focused in Electrification, Industrial Automation, Robotics, Discrete Automation 

and Motion”,”entry_date”:”2020-11-16T06:49:43.108992Z”,”robots”:[]}

Retrieve a manufacturer

Let’s compose a request to retrieve a manufacturer. The HTTPie command is:

http :8000/manufacturers/2

Output:

Retrieve a single manufacturer

The equivalent curl command is: 

curl -iX GET localhost:8000/manufacturers/2

Add robot details

We have populated the robot category and manufacturer details. Now, let’s compose and send a POST request to add robot details. The HTTPie command is 

http POST :8000/robots/ name=”FANUC M-710ic/50″ robot_category=”Articulated Robots” currency=”USD” price=37000 manufacturer=”FANUC Global” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Axes 6, Payload 50 KG, Reach 2050 MM”

Output:

Robot Entry (HTTP Utility Pie command)

Let’s compose a curl command to create a new entry.

curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”SR-3iA\”, \”robot_category\”:\”SCARA Robots\”, \”currency\”:\”USD\”, \”price\”:37000, \”manufacturer\”:\”FANUC Global\”, \”manufacturing_date\”:\”2019-10-12 00:00:00.000000+00:00\”, \”add_details\”:\”Axis 4, Payload 3 KG, Reach 400 MM\”}” localhost:8000/robots/

Output:

Let’s add a few more entries in Robot. The HTTPie commands are:

http POST :8000/robots/ name=”IRB 120″ robot_category=”Articulated Robots” currency=”USD” price=14500 manufacturer=”ABB” manufacturing_date=”2020-05-10 00:00:00.000000+00:00″ add_details=”Axes 6, Payload 3 KG, Reach 0.58m”

http POST :8000/robots/ name=”IRB 910SC” robot_category=”SCARA Robots” currency=”USD” price=25000 manufacturer=”ABB” manufacturing_date=”2020-05-10 00:00:00.000000+00:00″ add_details=”Axes 4, Payload 6 KG, Reach 0.65m”

Let’s look into the Robot, Robot Category, and Manufacturer list. 

http :8000/robots/

Robot List

http :8000/robot-categories/

Robot Category List

http :8000/manufacturers/

Manufacturer List

In robot categories and manufacturer entry, you can notice that the robots are mentioned in its URL form. 

PUT, PATCH, and DELETE Resources

Now let’s compose PUT, PATCH, and DELETE requests. We will add a new robot category (Test Category) and manufacturer (Test Manufacturer). The HTTPie command as follows:

http POST :8000/robot-categories/ name=”Test Category” notes=”Test”

http POST :8000/manufacturers/ name=”Test Manufacturer” rating=1 notes=”Test”

Let’s add a few robots that belong to the Test Category and Test Manufacturer. The HTTPie command as follows:

http POST :8000/robots/ name=”TEST 1″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”

http POST :8000/robots/ name=”TEST 2″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”

http POST :8000/robots/ name=”TEST 3″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”

Let’s check the entries in the database using the below psql command. 

select * from robots_robot;

Output:

You can notice that new entries are added to our database. 

PUT HTTP verb

Now let’s edit the last entry named TEST 3, which has 11 as the primary key, using the PUT HTTP verb.

The HTTPUtility Pie command is:

http PUT :8000/robots/11  name=”TEST 3″ robot_category=”Test Category” currency=”USD” price=12000 manufacturer=”Test Manufacturer” manufacturing_date=”2020-10-12 00:00:00.000000+00:00″ add_details=”Test3″

Output:

The equivalent curl command is

curl -iX PUT -H “Content-Type: application/json” -d “{\”name\”:\”TEST 3\”, \”robot_category\”:\”Test Category\”, \”currency\”:\”USD\”, \”price\”:12000, \”manufacturer\”:\”Test Manufacturer\”, \”manufacturing_date\”:\”2020-10-12 00:00:00.000000+00:00\”, \”add_details\”:\”Test3\”}” localhost:8000/robots/11

PATCH HTTP Verb

Let’s partially edit the resource that has primary key 11. The HTTPie command for PATCH request is:

http PATCH :8000/robots/11  price=15000 add_details=”Test3 Patch”

Output:

The equivalent curl command is:

curl -iX PATCH -H “Content-Type: application/json” -d “{ \”price\”:15000, \”add_details\”:\”Test3 Patch\”}” localhost:8000/robots/11

DELETE HTTP Verb

Now, let’s delete the entry that has primary key 11 using DELETE HTTP Verb. The HTTPie command is:

http DELETE :8000/robots/11

Output:

The equivalent curl command is 

curl -iX DELETE localhost:8000/robots/11

Now, we need to check what happens if a robot category is deleted. According to our code, if a category is deleted, then all the robots that belong to the particular category should also be cleared. Let’s delete our Test Category (the primary id 3). The HTTPie command is

http DELETE :8000/robot-categories/3

Output:

Let’s look at the robot table. In total, we added 3 robots (Test 1, Test 2, and Test 3) that belong to Test Category. The robot that has primary id 11 (Test 3) is already deleted using delete request. The remaining two robots with primary id 9 (Test 1) and 10 (Test 2) exist in the database. Since we deleted the Test Category, automatically the other two robots will be cleared from the table. Let’s check the database using the psql command.

select * from robots_robot;

Output:

You can notice that the robots belong to Test Category are cleared successfully. This is made possible with the help of the code, on_delete=models.CASCADE, mentioned while defining the robot category as a foreign key in the robot model.

Summary

In this article, we learned about generic class views to implement HTTP requests. For this, we used two generic class views from the rest_framework.generics module, ListCreateAPIView and RetrieveUpdateDestroyAPIView. And also we composed different HTTP requests to interact with related resources.



Last Updated : 27 Apr, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads