DJANGO
ENGINEER

Viewsets In Django Rest Framework

Time Spent- 12m
114 Visitors

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 viewsetsRouters 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_classes, authentication_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)
  1. GenericViewSet
  • Just like "ViewSet", It also does not provide the implementation of actions.
  • We ca use the attributes like permission_classes, authentication_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)
  1. 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_classesand authentication_classes.
  • If we any conditional logic then we can override methods like get_objectget_querysetget_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)
  1. StudentViewSet Urls
  • '^student-viewset/$'
  • '^student-viewset/(?P<pk>[^/.]+)/$'
  1. StudentGenericViewSet Urls
  • '^student-generic-viewset/$'
  • '^student-generic-viewset/(?P<pk>[^/.]+)/$'
  1. Student*ModelViewSet* 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.