viewsets in Django Rest Framework


viewsets in Django Rest Framework

ViewSets are one of the super cool features of  Django REST Framework. ViewSets are just a type of class based view but it do not provide request method handlers like "get()", "post()", "patch()", "delete()", etc. But, it provides actions such as "create()", "list()", "retrieve()", "update()", "partial_update()" and "destroy()". DRF allows us to combine the logic for a set of related views in a single class "ViewSet". ViewSets can speed-up the development and better maintainability. In class based views we map views to urls using url config (i.e path ), but where as in viewsets  we use routers to register the viewsets. Routers  simplifies the process of configuring the viewsets to urls. 

Advantages of ViewSets

  • Repeated functionality can be combined into a single class.
  • Routers are used to wiring up the url configurations so, we do not need to write url configurations externally.
  • For large API's we can enforce a consistent URL configuration throughout the API.

ViewSet classes in DRF

  1. ViewSet
    • It does not provide the any implemetations of actions. We have to override the class and define the action implementations explicitly. 
    • We ca use the attributes like permission_classesauthentication_classes

    • Example: Let's define a simple viewset that can be used to list or retrieve all the students in the school model.
      # models.py

      from django.db import models
      
      class Student(models.Model):
          name = models.CharField(max_length=100)
          age = models.PositiveIntegerField()
      
          def __str__(self):
             return "{name}".format(name=self.name)
      

      # serializers.py

      from rest_framework import serializers
      from .models import Student
      
      class StudentSerializer(serializers.ModelSerializer):
          class Meta:
              model = Student
              fields = ('id', 'name', 'age')
      

      # views.py

      from django.shortcuts import get_object_or_404
      from rest_framework import viewsets
      from rest_framework.response import Response
      from .models import Student
      from .serializers import StudentSerializer
      
      class StudentViewSet(viewsets.ViewSet):
      
          def list(self, request):
              queryset = Student.objects.all()
              serializer = StudentSerializer(queryset, many=True)
              return Response(serializer.data)
      
          def retrieve(self, request, pk=None):
              queryset = Student.objects.all()
              user = get_object_or_404(queryset, pk=pk)
              serializer = StudentSerializer(user)
              return Response(serializer.data)
  2. GenericViewSet

    • Just like "ViewSet", It also does not provide the implementation of actions.

    • We ca use the attributes like permission_classesauthentication_classes

    • The only difference between ViewSet and GenericViewSet is that it provides generic methods like `get_object` and `get_queryset`.

    • Example:
      # views.py

      from rest_framework import viewsets
      from rest_framework.response import Response
      from .models import Student
      from .serializers import StudentSerializer
      
      class StudentGenericViewSet(viewsets.GenericViewSet):
      
         def get_queryset(self):
             queryset = Student.objects.all()
             return queryset
      
         def get_object(self):
             queryset = self.get_queryset()
             obj = queryset.get(pk=self.kwargs['pk'])
             return obj
         
         def list(self, request):
             queryset = self.get_queryset()
             serializer = StudentSerializer(queryset, many=True)
             return Response(serializer.data)
      
         def retrieve(self, request, **kwargs):
             obj = self.get_object()
             serializer = StudentSerializer(obj)
             return Response(serializer.data)
      
  3. ModelViewSet

    • It provides all the actions by default (i.e   .list().retrieve().create().update().partial_update(), and .destroy()).

    • Most of the times we use this because it provides the generic functionality so, we simply need to override the attributes like  ` queryset` , `serializer_class` , `permission_classes`and `authentication_classes`.

    • If we any conditional logic then we can override methods like `get_object`, `get_queryset`, `get_permission_classes`,  etc.

    • Example:
      # views.py

      from rest_framework import viewsets
      from .models import Student
      from .serializers import StudentSerializer
      
      class StudentModelViewSet(viewsets.ModelViewSet):
          queryset = Student.objects.all()
          serializer_class = StudentSerializer
      

So, our viewsets are ready to go. But, we have not configured the urls. Yes, lets do this with Django Rest "Routers".  

# urls.py

from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register('student-viewset', views.StudentViewSet, basename='student_vs')
router.register('student-generic-viewset', views.StudentGenericViewSet, basename='student_gvs')
router.register('student-model-viewset', views.StudentModelViewSet, basename='student_mvs')
urlpatterns = router.urls
# print(urlpatterns)

Router generates urls like below

  1. StudentViewSet Urls
    • '^student-viewset/$'
    • '^student-viewset/(?P<pk>[^/.]+)/$'
  2.  StudentGenericViewSet Urls
    • '^student-generic-viewset/$'
    • '^student-generic-viewset/(?P<pk>[^/.]+)/$'
  3. StudentModelViewSet Urls
    • '^student-model-viewset/$'
    • '^student-model-viewset/(?P<pk>[^/.]+)/$'

For "StudentViewSet" and "StudentGenericViewset" we have implemeted two actions (i.e list and retrieve) only. so, we can only retrieve the resources. But, where as in "StudentModelViewset" we have inherited the "ModelViewSet" so it also provides functionalities like create update and partial update in addition to list and retrieve. so, try it on your own. You can find the sample project on github. I will write more about "Django REST Routers"in the next article.

Read Next: django send email using mailgun api

Read Prev: permissions in Django Rest Framework

Blog Archive