Class based views - Django Rest Framework - GeeksforGeeks

16 Feb, 2021
Class-based views help in composing reusable bits of behavior. Django REST Framework provides several pre-built views that allow us to reuse common functionality and keep our code DRY. In this section, we will dig deep into the different class-based views in Django REST Framework.
This article assumes you are already familiar with Django and Django REST Framework. 
Checkout – 
Django tutorial 
Create a basic API using Django Rest Framework 
APIView class provides commonly required behavior for standard list and detail views. With APIView class, we can rewrite the root view as a class-based view. They provide action methods such as get(), post(), put(), patch(), and delete() rather than defining the handler methods.
Let’s take a look at how to create views using APIView. The views.py file module as follows:
Python3
from django.shortcuts import renderfrom django.http import Http404  from rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import status  from transformers.models import Transformerfrom transformers.serializers import TransformerSerializer  class TransformerList(APIView):    """    List all Transformers, or create a new Transformer    """      def get(self, request, format=None):        transformers = Transformer.objects.all()        serializer = TransformerSerializer(transformers, many=True)        return Response(serializer.data)      def post(self, request, format=None):        serializer = TransformerSerializer(data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data,                            status=status.HTTP_201_CREATED)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  class TransformerDetail(APIView):    """    Retrieve, update or delete a transformer instance    """    def get_object(self, pk):        # Returns an object instance that should         # be used for detail views.        try:            return Transformer.objects.get(pk=pk)        except Transformer.DoesNotExist:            raise Http404      def get(self, request, pk, format=None):        transformer = self.get_object(pk)        serializer = TransformerSerializer(transformer)        return Response(serializer.data)      def put(self, request, pk, format=None):        transformer = self.get_object(pk)        serializer = TransformerSerializer(transformer, data=request.data)        if serializer.is_valid():            serializer.save()            return Response(serializer.data)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)      def patch(self, request, pk, format=None):        transformer = self.get_object(pk)        serializer = TransformerSerializer(transformer,                                           data=request.data,                                           partial=True)        if serializer.is_valid():            serializer.save()            return Response(serializer.data)        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)                def delete(self, request, pk, format=None):        transformer = self.get_object(pk)        transformer.delete()        return Response(status=status.HTTP_204_NO_CONTENT)
The code is similar to regular Django views, but there is a better separation between different HTTP Methods.
The get() method process the HTTP GET request
The  post() method process the HTTP POST request
The put() method process the HTTP PUT request
The patch() method process the HTTP PATCH request
The delete() method process the HTTP DELETE request
Since we are using class-based views the way we mention the views in the path of the urls.py file is slightly different. Create a new file named urls.py (if not exist) in the app (transformers) folder and add the below code
Python3
from django.urls import pathfrom rest_framework.urlpatterns import format_suffix_patternsfrom transformers import views  urlpatterns = [    path('transformers/', views.TransformerList.as_view()),    path('transformers/<int:pk>/', views.TransformerDetail.as_view()),]  urlpatterns = format_suffix_patterns(urlpatterns)
Next, set up the root URL configuration. You can open the urls.py (same folder where the settings.py file is  located) and add the below code
Python3
from django.contrib import adminfrom django.urls import path, include  urlpatterns = [    path('', include('transformers.urls')),]
The HTTPie command is:
http POST :8000/transformers/ name=”Optimus Prime” alternate_mode=”1979 Freightliner Semi” description=”Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader” alive=”True”
Output
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 194
Content-Type: application/json
Date: Sat, 23 Jan 2021 03:48:46 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}
Sharing the command prompt screenshot for your reference:
The pk value of Optimus Prime is 1. Let’s pass the pk value and retrieve the details
The HTTPie command is:
http GET :8000/transformers/1/
Output
HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS
Content-Length: 194
Content-Type: application/json
Date: Sat, 23 Jan 2021 03:50:42 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}
Sharing the command prompt screenshot for your reference
Let’s update the field named alive by setting it to False. The HTTPie command is:
 http PUT :8000/transformers/1/ name=”Optimus Prime” alternate_mode=”1979 Freightliner Semi” description=”Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader” alive=”False”
Output
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 195
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:22:30 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous of all Autobots, he is also their leader",
    "id": 1,
    "name": "Optimus Prime"
}
Sharing the command prompt screenshot for your reference
Let’s partially update the field named description. The HTTPie command is:
http PATCH :8000/transformers/1/ description=”Optimus Prime is the strongest and most courageous and leader of all Autobots”
Output
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 181
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:32:40 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": "1979 Freightliner Semi",
    "description": "Optimus Prime is the strongest and most courageous and leader of all Autobots",
    "id": 1,
    "name": "Optimus Prime"
}
Sharing the command prompt screenshot
We will create a new entry and delete it. Let’s create a ‘Test’ entry using the below HTTPie command:
http POST :8000/transformers/ name=”Test”
Output
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 77
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:34:41 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": false,
    "alternate_mode": null,
    "description": null,
    "id": 2,
    "name": "Test"
}
Now let’s delete the ‘Test’ entry (pk =2). The HTTPie command to delete entry is
http DELETE :8000/transformers/2/
Output
HTTP/1.1 204 No Content
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 0
Date: Sat, 23 Jan 2021 04:35:06 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Sharing the command prompt screenshot
Mixin classes allow us to compose reusable bits of behavior. They can be imported from rest_framework.mixins. Let’s discuss the different types of mixin classes
ListModelMixin : It provides a .list(request, *args, **kwargs) method for listing a queryset.  If the queryset is populated, the response body has a 200 OK response with a serialized representation of the queryset.
CreateModelMixin: It provides a .create(request, *args, **kwargs) method for creating and saving a new model instance. If the object is created, the response body has a 201 Created response, with a serialized representation of the object. If invalid, it returns a  400 Bad Request response with the error details.
RetrieveModelMixin: It provides a .retrieve(request, *args, **kwargs) method for returning an existing model instance in a response. If an object can be retrieved, the response body has a 200 OK response, with a serialized representation of the object. Otherwise, it will return a 404 Not Found.
UpdateModelMixin: It provides a .update(request, *args, **kwargs) method for updating and saving an existing model instance. It also provides a .partial_update(request, *args, **kwargs) method for partially updating and an existing model instance. . If the object is updated, the response body has a 200 OK response, with a serialized representation of the object. Otherwise, 400 Bad Request response will be returned with the error details.
DestroyModelMixin: It provides a .destroy(request, *args, **kwargs) method for deleting an existing model instance. If an object is deleted, the response body has a 204 No Content response, otherwise, it will return a 404 Not Found.
Note: We will be using GenericAPIView to build our views and adding in Mixins. 
Let’s take a look at how we can make use of Mixin classes. The views.py file module as follows:
Python3
from rest_framework import mixinsfrom rest_framework import genericsfrom transformers.models import Transformerfrom transformers.serializers import TransformerSerializer  class TransformerList(mixins.ListModelMixin,                      mixins.CreateModelMixin,                      generics.GenericAPIView):    queryset = Transformer.objects.all()    serializer_class = TransformerSerializer      def get(self, request, *args, **kwargs):        return self.list(request, *args, **kwargs)      def post(self, request, *args, **kwargs):        return self.create(request, *args, **kwargs)  class TransformerDetail(mixins.RetrieveModelMixin,                        mixins.UpdateModelMixin,                        mixins.DestroyModelMixin,                        generics.GenericAPIView):    queryset = Transformer.objects.all()    serializer_class = TransformerSerializer      def get(self, request, *args, **kwargs):        return self.retrieve(request, *args, **kwargs)      def put(self, request, *args, **kwargs):        return self.update(request, *args, **kwargs)      def patch(self, request, *args, **kwargs):        return self.partial_update(request, *args, **kwargs)      def delete(self, request, *args, **kwargs):        return self.destroy(request, *args, **kwargs)
Here, the GenericAPIView class provides the core functionality, and we are adding mixin classes to it. The queryset and serializer_class are the basic attributes of GenericAPIView class. The queryset attribute is used for returning objects from this view and the serializer_class attribute is used for validating, deserializing input, and for serializing output.
In the TransformerList class, we make use of mixin classes that provide .list() and .create() actions and bind the actions to the get() and post() methods. In the TransformerDetail class we make use of mixin classes that provide .retrieve(), .update(), .partial_update(), and . destroy() actions and bind the actions to get(), put(), patch(), and delete() methods.
The HTTPie command is
http POST :8000/transformers/ name=”Bumblebee” alternate_mode=”1979 VW Beetle” description=”Small, eager, and brave, Bumblebee acts as a messenger, scout, and spy” alive=”True”
Output
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 161
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:58:26 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 VW Beetle",
    "description": "Small, eager, and brave, Bumblebee acts as a messenger, scout, and spy",
    "id": 3,
    "name": "Bumblebee"
}
The HTTPie command is
http GET :8000/transformers/
Output
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 345
Content-Type: application/json
Date: Sat, 23 Jan 2021 04:59:42 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

[
    {
        "alive": true,
        "alternate_mode": "1979 VW Beetle",
        "description": "Small, eager, and brave, Bumblebee acts as a messenger, scout, and spy",
        "id": 3,
        "name": "Bumblebee"
    },
    {
        "alive": false,
        "alternate_mode": "1979 Freightliner Semi",
        "description": "Optimus Prime is the strongest and most courageous and leader of all Autobots",
        "id": 1,
        "name": "Optimus Prime"
    }
]
Sharing the command prompt screenshot for your reference
To make use of generic class-based views, the view classes should import from rest_framework.generics.
CreateAPIView: It provides a  post method handler and it is used for create-only endpoints. CreateAPIView extends GenericAPIView and CreateModelMixin
ListAPIView: It provides a get method handler and is used for read-only endpoints to represent a collection of model instances. ListAPIView extends GenericAPIView and ListModelMixin.
RetrieveAPIView: It provides a get method handler and is used for read-only endpoints to represent a single model instance. RetrieveAPIView extends GenericAPIView and RetrieveModelMixin.
DestroyAPIView: It provides a delete method handler and is used for delete-only endpoints for a single model instance. DestroyAPIView extends GenericAPIView and DestroyModelMixin.
UpdateAPIView: It provides put and patch method handlers and is used for update-only endpoints for a single model instance. UpdateAPIView extends GenericAPIView and UpdateModelMixin.
ListCreateAPIView: It provides get and post method handlers and is used for read-write endpoints to represent a collection of model instances. ListCreateAPIView extends GenericAPIView, ListModelMixin, and CreateModelMixin..
RetrieveUpdateAPIView: It provides get, put, and patch method handlers. It is used to read or update endpoints to represent a single model instance. RetrieveUpdateAPIView extends GenericAPIView, RetrieveModelMixin, and UpdateModelMixin.
RetrieveDestroyAPIView: It provides get and delete method handlers and it is used for read or delete endpoints to represent a single model instance. RetrieveDestroyAPIView extends GenericAPIView, RetrieveModelMixin, and DestroyModelMixin.
RetrieveUpdateDestroyAPIView: It provides get, put, patch, and delete method handlers. It is used for read-write-delete endpoints to represent a single model instance. It extends GenericAPIView, RetrieveModelMixin, UpdateModelMixin, and DestroyModelMixin.
Let’s take a look at how we can make use of Mixin classes. Here we will take advantage of  ListCreateAPIView and RetrieveUpdateDestroyAPIView. The views.py file module as follows:
Python3
from rest_framework import generics  from transformers.models import Transformerfrom transformers.serializers import TransformerSerializer  class TransformerList(generics.ListCreateAPIView):    queryset = Transformer.objects.all()    serializer_class = TransformerSerializer  class TransformerDetail(generics.RetrieveUpdateDestroyAPIView):    queryset = Transformer.objects.all()    serializer_class = TransformerSerializer
You can notice that we were able to avoid a huge amount of boilerplate code. These generic views combine reusable bits of behavior from mixin classes. Let’s look at the declaration of ListCreateAPIView and RetrieveUpdateDestroyAPIView:
class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
   ......

class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
                                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                                   GenericAPIView):
  ......
The HTTPie command is
http POST :8000/transformers/ name=”Cliffjumper” alternate_mode=”1979 Porsche 924′′ description=”His eagerness and daring have no equal” alive=”True”
Output
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 133
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:28:45 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Porsche 924",
    "description": "His eagerness and daring have no equal",
    "id": 5,
    "name": "Cliffjumper"
}
Sharing the command prompt screenshot for your reference
The HTTPie command is
http PUT :8000/transformers/5/ name=”Cliffjumper” alternate_mode=”1979 Porsche 924′′ description=”Eager and Daring” alive=”True”
Output
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 111
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:35:39 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 Porsche 924",
    "description": "Eager and Daring",
    "id": 5,
    "name": "Cliffjumper"
}
Sharing the command prompt screenshot for your reference
http PATCH :8000/transformers/3/ alive=”True”
Output
HTTP/1.1 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Length: 151
Content-Type: application/json
Date: Sat, 23 Jan 2021 05:37:54 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY

{
    "alive": true,
    "alternate_mode": "1979 VW Beetle",
    "description": "Small, eager, and brave. Acts as a messenger, scout, and spy",
    "id": 3,
    "name": "Bumblebee"
}
Sharing the command prompt screenshot for your reference
In this section, we explored different types of class-based views provided by the Django REST Framework. We implemented views using APIView and explained different types of mixin classes. Finally, we revealed various types of generic class-based views and demonstrated how they avoid a huge amount of boilerplate code.
Django-REST
Python Django
Python
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
How to Install PIP on Windows ?
How to drop one or multiple columns in Pandas Dataframe
How To Convert Python Dictionary To JSON?
Check if element exists in list in Python
Python | Pandas dataframe.groupby()
Python | Get unique values from a list
Defaultdict in Python
Python | os.path.join() method
Python Classes and Objects
Create a directory in Python