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_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)
    
  2. 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)
    
  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_classesand 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)
  1. StudentViewSet Urls

    • '^student-viewset/$'
    • '^student-viewset/(?P<pk>[^/.]+)/$'
  2. StudentGenericViewSet Urls

    • '^student-generic-viewset/$'
    • '^student-generic-viewset/(?P<pk>[^/.]+)/$'
  3. 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.