Post

Django REST Framework Notes

Django REST Framework Notes

Quick Introduction

Jargons

  1. API: Application Programming Interface is a shorthand way to describe how two computers communicate directly with one another.
  2. REST: REpresentational State Transfer
  3. ASGI: Asynchronous Server Gateway Interface
  4. WSGI: Web Server Gateway Interface
  5. CORS: Cross-Origin Resource Sharing is a mechanism that lets web pages access resources from other domains.
  6. CSRF: Cross-Site Request Forgery is a malicious exploit that tricks a user’s browser into performing unwanted actions on a trusted website. It’s also known as XSRF.

Web APIs

URLs (Uniform Resource Locator)

For example, the following url https://zhengyuan.xin/api/ has three components:

  1. Scheme: https
  2. Hostname: zhengyuan.xin
  3. (Optional) Path: /api/

HTTP Verbs

CRUDHTTP Verbs
CreatePOST
ReadGET
UpdatePUT
DeleteDELETE

Request/Response

1
2
3
4
Request/Response Line
Headers

(Optional) Body

Status Code

  • 2XX: Success
  • 3XX: Redirection
  • 4XX: Client Error
  • 5XX: Server Error

DRF

Serializer

  • Complex datatypes (querysets or model instances) serialize into Python datatypes (then converted into JSON/XML).
  • Incoming JSON/XML data unserialize into Python objects.

There are two types of view, function-based and class-based.

Function-based Views

1
2
3
4
5
6
7
8
9
10
11
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import UserRateThrottle


class OncePerDayUserThrottle(UserRateThrottle):
    rate = '1/day'

@api_view(['GET', 'POST'])
@throttle_classes([OncePerDayUserThrottle])
def view(request):
    return Response({"message": "Hello for today! See you tomorrow!"})

Use decorators to wrap your function-based views to ensure they receive DRF’s Request instances.

Class-based Views

Views

APIView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User


class ListUsers(APIView):
    authentication_classes = [authentication.TokenAuthentication]
    permission_classes = [permissions.IsAdminUser]

    def get(self, request, format=None):
        """
        Return a list of all users.
        """
        usernames = [user.username for user in User.objects.all()]
        return Response(usernames)
  • APIView is the base class in DRF
  • Handler methods: get(), post(), put(), delete()
    • receives request, which is DRF’s Request instance, not Django’s HttpRequest.
    • returns DRF’s Response instance, not Django’s HttpResponse instance.
  • Full control over the request handling process.
  • Source code: views.py, decorators.py

Generic Views

GenericAPIView

1
2
3
4
5
6
7
8
9
10
11
12
13
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer


class MyGenericAPIView(GenericAPIView):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

    def get(self, request):
        serializer = self.get_serializer(self.get_queryset(), many=True)
        return Response(serializer.data)
  • Subclass of APIView
  • Add support for queryset for database queries.
  • Add support for serializer_class to determine which serializer to use.
  • Built-in support for Pagination, Filtering, and Ordering.
  • Source code: generics.py, mixins.py

Mixin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer


class MyMixinView(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
  • Mixins are used with GenericAPIView and they provide actions rather than handler methods
  • Common mixins:
    • CreateModelMixin => .list()
    • ListModelMixin => .create()
    • RetrieveModelMixin => .retrieve()
    • UpdateModelMixin => .update() and .partial_update()
    • DestroyModelMixin => .destroy()

Concrete View Classes

  • CreateAPIView
  • ListAPIView
  • RetrieveAPIView
  • DestroyAPIView
  • UpdateAPIView
  • ListCreateAPIView
  • RetrieveUpdateAPIView
  • RetrieveDestroyAPIView
  • RetrieveUpdateDestroyAPIView

ViewSets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# views.py
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response


class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

# urls.py
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter


router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls
  • ViewSet provide actions rather than handler methods
This post is licensed under CC BY 4.0 by the author.