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

Generic, Functional Based and Class Based Views in Django REST Framework

2022-07-19

Django-Rest-Framework(DRF) supports three different types of views. They are

  1. Function Based Views
  2. Class Based Views / Generic Views
  3. ViewSets

Based on the developer convenience developer can choose the type of view.

Function based views(FBV):

  • Our view should return the response as per the standards of the django rest framework (Response but not reggular HttpResponse). 
  • Django REST provides a set of decorators that will check whether the view returning the correct Response or not.
  • Django REST provides the following decorators
  • api_view, renderer_classes, parser_classes, authentication_classes,
  • throttle_classes, permission_classes, detail_route, list_route
  • @api_view: It converts the function based view into a subclass of API view.
  • @renderer_classes: It takes an iterable set of renderer classes which helps in creating response to a request with various media types.
  • @parser_classes: It takes an iterable set of parser classes which allows REST to accept requests with different  various media types.
  • @authentication_classes: It takes an iterable set of authentication classes that will allow REST authenticate the request.
  • @throttle_classes: It takes an iterable set of throttle classes that will limit number of requests per user in a specific amount of time.
  • @permission_classes: It takes an iterable set of permission classes that allows REST to check whether user allowed to take the requested resource or not.
  • @detail_route: It  will mark the function/method to be served for detail request.
  • @list_route: It  will mark the function/method to served for list request.
  • All other decorators must come after @api_view
  • Every decorator takes a single argument which must be a list or tuple of classes except @detail_route, @list_route
  • We need to configure the urls for FBV views.

Generic Views(Class Based Views - CBV):

  • REST class based views are just like django class based views.
  • Every incoming request will be dispatched to the appropriate method handler just like django CBV.
  • APIView is  the base class for all the DRF CBV and GenericAPIView is the base class for all the generic CBV.
  • Following are the generic views provided by the DRF
  • CreateAPIView, ListAPIView, RetrieveAPIView, DestroyAPIView, UpdateAPIView, ListCreateAPIView,
  • RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView
  • CreateAPIView:
    • Inherit this class only if you want to create a model instance.
    • Just like CreateView in django.
    • Only allows the request type "POST".
  • ListAPIView:
    • Inherit this class only if you want to retrieve list of model instances.
    • It works just like ListView in django.
    • You can override the method "get_queryset" if you want conditional queryset to be returned.
    • It only allows the request type "GET"
  • RetrieveAPIView:
    • Inherit this class only if you want to retrieve details of a specific model instance.
    • You have to provide a unique identifier as a argument in the url.
    • It works just like DetailView in django.
    • It only allows the request type "GET"
  • DestroyAPIView:
    • Inherit this class only if you want to delete a model instance.
    • You have to provide a unique identifier as a argument in the url.
    • It only allows the request type "DELETE"
  • UpdateAPIView:
    • Inherit this class only if you want to update a model instance.
    • You have to provide a unique identifier as a argument in the url.
    • Use request type "PUT" for complete update of model instance.
    • Use request type "PATCH" for partial update.
    • It only allows the request types "PUT", "PATCH"
  • ListCreateAPIView:
    • Inherit this class if you want to create a list of model instances at  once.
    • It only allows the request types "GET", "POST"
    • Use request type "POST" for creating the list of model instances.
    • Use request type "GET" for retrieving the list of model instances. 
  • RetrieveUpdateAPIView:
    • Inherit this class if you want both functionalities retriving and updating the model instance.
    • It allows request type "GET", "PUT", "PATCH"
  • RetrieveDestroyAPIView:
    • Inherit this class if you want both functionalities retriving and deleting the model instance.
    • It allows request type "GET", "DELETE"
  • RetrieveUpdateDestroyAPIView:
    • Inherit this class if you want the three functionalities retrive, update, delete for the same url.
    • It allows request type "GET", "DELETE", "PUT" and "PATCH"
  • Inherit the above mentioned classes based on your requirement.
  • Unlike in FBV we do not use decorators instead we use class attributes for rendereres, permissions, parsers, throttles, etc.
  • To customise default behaviour of the DRF by overriding the appropriate methods and attributes.
  • We need to configure the urls for CBV views.
  • To use CBV  we must have basic understanding of Object Oriented Programming.

ViewSets:

  • ViewSets works exactly same as generic views(CBV). The only difference is that it allows us to combine the logic for set of related views in a single class.
  • It does not provide method handlers like "get", "post", "put", etc.
  • We do not configure the urls with ViewSets instead we use Routers to register viewsets.
  • Routers generates urls for ViewSets automatically  and binds methods like "retrieve", "list", "create", "update", "delete", "partial_upate" for different request method types(GET, POST, etc).
  • DRF provides three generic viewsets GenericViewSet, ReadOnlyModelViewSet, ModelViewSet.
  • GenericViewSet:
    • It does not include the basic actions/methods like "list", "create", etc. we have to define these methods  in order to use it.
    • But It provides methods like "get_object" and "get_queryset"
    • Inherit it and use it only if you want to implement completly new behaviour rather than the basic behaviour provided by DRF.
  • ReadOnlyModelViewSet:
    • It provides the functionality of CBV views ListAPIView and RetrieveAPIView in a single class.
    • It accepts only accepts the request method type "GET"
  • ModelViewSet:
    • It provides complete functionality of CBV of DRF in a single class.
    • You can avoid writing of six different classes.
    • You can also avoid configuring of urls for classes.

Examples: create user with django-rest-framework

# serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ("first_name", "last_name", "email")

# function based views.py
from django.contrib.auth.models import User
from .serializers import UserSerializer
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated

@api_view(['POST'])
# other decorators if required
@permission_classes([IsAuthenticated])
def user_create(request):
    serializer = UserSerializer(data=request.POST)
    if serializer.is_valid():
        password = serializer.validated_data.get("password")
        serializer.object.set_password(password)
        serializer.save()
        return Response({"message": "User Created"}, status=status.HTTP_201_CREATED)
    else:
        return Response(serializer.errors)

# function based urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
   url(r'^user-create/$',  views.user_create, name="user-create"),
]

# generic views.py
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from .serializers import UserSerializer

class UserCreateView(generics.CreateAPIView):
    serializer_class = UserSerializer
    permission_classes = (IsAuthenticated, )

# generic urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
   url(r'^user-create/$',  views.UserCreateView.as_view(),  name="user-create"),
]
# viewsets.py
from rest_framework import viewsets

class UserViewSet(viewsets.ModelViewSet):
   serializer_class = UserSerializer
   permission_classes = (IsAuthenticated, )

# viewsets urls.py
from django.conf.urls import url, include
from rest_framework import routers
from . import viewsets

router = routers.DefaultRouter()
router.register(r'users', viewsets.UserViewSet)

urlpatterns = [
    url(r'^', include(router.urls)),
]

If you observe the above example code you can absorve that we have to write complete code inorder to get the full functionality even if it is a common case. But where as in generic views we can avoid the writing of repetitive code for common cases. In both the generic views and function based views we configured the urls with views. But, In viewsets we registered the ViewSet class with register. The advantage of register is that it can generate the urls & binds the appropriate methods to different request method types. If you are dealing with large project more number of views and url configurations. It will make maintenace of project difficult. By using Routers and ViewSets we can better maintain the project though it deals with a little abstraction.