Django REST framework views

·

4 min read

In this article I want to discuss django REST framework views: what they are, how they differ from django views, and the different ways that they can be implemented.

Views

Views are functions or class methods that receive HTTP request, process a logic and return an HTTP response. Django provides two types of views: function-based views and class-based views. While the choice depends mainly on the usecase, class-based views have obvious advantage of reusability.

Django REST framework views

Django REST framework views differ from django views for the following reasons:

  • The request handler view receives a rest_framework.requests.Request instance and not django's HttpRequest instance. And the response is instance of rest_framework.reponse.Response and not django's HttpResponse

  • Incoming requests can be authenticated and permissions can be checked before dispatch

  • REST framework views negotiate the response content type such as JSON, html or other based on the request.
  • APIExceptions are caught and converted to responses that contain relevant error messages

Django REST framework views can be implemented as

  1. Function based views
  2. Class based views
  3. ViewSets

Function based views

Are defined using rest_framework.decorators.api_view decorator. Attributes such as renderer, parser, authentication, throttle, permission, schema can be configured using the decorators: .renderer_classes, .parser_classes, .authentication_classes, .throttle_classes, .permission_classes, .content_negotiation_class respectively.

from .models import Category
from .serializers import CategorySerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET', 'POST'])
def categoryView(request):
    """
    List all categories or create a category
    """
    if request.method == 'GET':    
        serializer = CategorySerializer(Category.objects.all(), many=True)
        return Response(serializer.data)
    else:
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response({'errors': serializer.errors})

Class based views

One way to define a class based API view is by inheriting from rest_framework.views.APIView. The request to the view is routed to one of the appropriate methods: .get(), .post(), .put(), .patch(), .delete() accordingly.

from .models import Category
from .serializers import CategorySerialzer
from rest_framework.views import APIView
from rest_framework.response import Response

class CategoyView(APIView):
    """
    List all categories or create a category
    """
    def get(self, request):
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response({"errors": serializer.errors})

The second way is by inheriting from one of the generic views of the module rest_framework.generics. The generic views provide shortcuts to the usual CRUD operations. Thus, the actual view ends up having way less code than the above.

from .models import Category
from .serializers import CategorySerialzer
from rest_framework import generics
from rest_framework.response import Response

class CategoryListView(generics.ListCreateAPIView):
    """
    List all categories or create a category
    """
    queryset = Category.objects.all()
    serializer_class = CategorySerialzer

class CategoryDetailView(generics.RetrieveUpdateDestroyAPIView):
    """
    Retrieve, update or delete a category
    """
    queryset = Category.objects.all()
    serializer_class = CategorySerialzer

ViewSets

ViewSets are much like what is known as a "controller" in MVC (Model View Controller) design pattern. They combine multiple related views into one class, avoiding repetition. They provide action methods such as .list(), .retrieve() and .create() instead of the HTTP methods. The relevant urls for these methods can be generated automatically using rest_framework.routers.

ViewSets can be defined by extending rest_framework.ViewSet or rest_framework.ModelViewSet. The later provides a default set of behaviours that there is no need to explicitly write the action methods.

from userreviews.models import Category
from .serializers import CategorySerializer
from rest_framework import viewsets

class CategoryViewSet(viewsets.ViewSet):
    """
    A viewset to list all categories or create, retrieve, update, delete a category
    """
    def list(self, request):
        queryset = Category.objects.all()
        serializer = CategorySerializer(queryset, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response({"error": serializer.errors})

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

A much shorter version of the above using .ModelViewSet

from userreviews.models import Category
from .serializers import CategorySerializer
from rest_framework import viewsets

class CategoryViewSet(viewsets.ModelViewSet):
     """
     A viewset to list all categories or create, retrieve, update, delete a category
     """
     queryset = Category.objects.all()
     serializer_class = CategorySerializer

Summary

Django rest framework views can be implemented as function based views, class-based views or viewsets. In general, class based views provide code reusability. And while viewsets combine related view logics into a single class and provide the ability to automatically generate url configurations, the basic class-based views provide more control and are explicit.