Viewsets

Viewsets in Django Rest Framework

Viewsets In 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, but where as in viewsetsarrow-up-right we use routers to register the viewsets. Routersarrow-up-right 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 any implementations of actions. We have to override the class and define the action implementations explicitly.

  • We can use the attributes like permission_classes, authentication_classes

  • Example: Let's define a simple viewsets 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.

3. ModelViewSet

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

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

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

Private date visible to the owning user

Implementation: The best place to filter the queryset is to override get_queryset method

Different serializers for different methods within a viewset

override get_serializer_class recommended

Add fields on the fly that aren't present on the model

Using queryset annotation

Using method on a serializer

There is an easy way with drf to do this with SerializerMethodField.

Add a field to serialized data that requires custom logic

How to do it"

  • define a field as serializers.SerializerMethodField()

  • add it to fields list in Meta

  • define get_myfieldname method

Pass additional data to the serializer

  • Use additional data to generate and an additional field

  • Perform additional validation

override get_serializer_context , the data can come e.g. from self.request, self.request.user of self.request.query_params

Use a serializer for the query parameters

Serializers transform data between formats such as JSON and native python, they also provide a good place to put your validation logic. we can use a serializer to extract and validate data from the query parameters (also known as URL params).

Use string value in an API for a field that has more efficient DB representation (enum)

If a field can only have a limited number of options, enums are a great choice. Django provides TextChoices, IntegerChoices, and Choices to make it very easy. My preferred field is the IntegerChoices because it will end up using much less space in the database even if the represented value is a string.

Unique together with a user that is not set in the form

Resources

Last updated