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
-
- 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)
-
-
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
andget_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)
-
-
-
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
andauthentication_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)
-
StudentViewSet Urls
'^student-viewset/$'
'^student-viewset/(?P<pk>[^/.]+)/$'
-
StudentGenericViewSet Urls
'^student-generic-viewset/$'
'^student-generic-viewset/(?P<pk>[^/.]+)/$'
-
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.