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 –
APIView
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.
Creating views using APIView
Let’s take a look at how to create views using APIView. The views.py file module as follows:
Python3
from django.shortcuts import render from django.http import Http404 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from transformers.models import Transformer from 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
Setting URL Configuration
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 path from rest_framework.urlpatterns import format_suffix_patterns from 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 admin from django.urls import path, include urlpatterns = [ path(' ', include(' transformers.urls')), ] |
Composing and sending HTTP Requests
1. Create a new entry –
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:
2. Retrieve an existing entry
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
3. Update an existing entry
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
4. Update partially an existing entry
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
5. Delete an existing entry
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
Mixins
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.
Creating Views using 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 mixins from rest_framework import generics from transformers.models import Transformer from 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.
Composing and Sending HTTP Requests
1. Create a new entry
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" }
2. Retrieve all entries
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
Generic class-based views
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.
Creating views using generic class-based views
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 Transformer from 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): ......
Composing and sending HTTP Requests
1. Create a new entry
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
2. Update an existing entry
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
3. Partially update an existing entry
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.
<!–
–>
Please Login to comment…