This page looks best with JavaScript enabled

Getting Started with Django REST Framework

 ·  ☕ 2 min read

In the SaaS development I work on, there is a fairly high demand for development efficiency. From project initiation, prototype design and evaluation, requirements confirmation, frontend design, and backend development through to final acceptance, we complete one iteration in just a few weeks. Guided by agile development, we began rolling out a frontend-backend separation model. The frontend focuses on pages and interaction, and the backend focuses on API interfaces. The backend provides APIs, which involve a whole series of concerns such as authentication, parameter validation, exception handling, and pagination. At the same time, these features share commonality across projects, so finding a suitable API scaffold became urgent. I previously looked into Django Restful APIs with Tastypie. Compared with Tastypie’s simplicity and quick onboarding, Django REST Framework (DRF) requires more configuration but is more powerful and can be used for rapid API development.

1. Feature Overview

  • Supports OAuth authentication
  • Supports serialization of ORM and non-ORM data sources
  • Rich customization hierarchy: function views, class views, view sets
  • Built-in Mixins for rapid assembly

2. Basic Concepts

  • Serializer

Serialization is the conversion of Python data structures into other data formats, for example mapping a Django Model to JSON.

Serialization provides data validation and rendering. It works in a way similar to Django Form, performing field validation based on Fields. The serialized data is stored in serializer.data, and you can use SomeRenderer().render(serializer.data) to serialize it into a string object to return as the Response body.

  • ViewSet

DRF provides API interfaces through Views. One View can correspond to multiple Renderers, providing different output formats (HTML/XML/JSON) for different rendering conditions.

A ViewSet is a wrapper around a View. One ViewSet can provide different interfaces for the same URL based on the request method. In particular, ModelViewSet automatically generates REST interfaces and URLs from the Model definition, making it possible to quickly generate a whole set of APIs for a website.

  • Request object.

DRF uses the Requests object to extend the native HttpRequest and provides more flexible request handling. The core attribute of the Requests object is request.data, which can handle arbitrary data and accepts POST, PUT, and PATCH methods.

3. DRF Processing Flow

4. Using DRF

Using DRF mainly consists of three steps: define resources - implement HTTP methods - configure URLs.

4.1 Installation and Configuration

1
pip install djangorestframework

In settings.py, add to INSTALLED_APPS:

1
2
3
4
5
INSTALLED_APPS = (
    ...
    'rest_framework',
    ...
)

4.2 Defining Resources and Implementing Serialization

models.py

1
2
3
4
5
from django.db import models

class Fruit(models.Model):
    name = models.CharField(u'名称', default="", max_length=255)
    price = models.FloatField(u"单价", default=0)

serializers.py

1
2
3
4
5
6
7
from rest_framework import serializers
from .models import Fruit

class FruitSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Fruit
        fields = ('name', 'price')

4.3 Inheriting View and Overriding HTTP Methods

views.py

1
2
3
4
5
6
7
from rest_framework.viewsets import ModelViewSet
from .models import Fruit
from .serializers import FruitSerializer

class FruitViewSet(ModelViewSet):
    queryset = Fruit.objects.all()
    serializer_class = FruitSerializer

FruitViewSet directly inherits from ModelViewSet, and ModelViewSet inherits the HTTP methods of a series of Mixins classes. If you need custom HTTP methods, you can inherit from the APIView class or the Mixins classes, or you can fully customize them.

4.4 Configuring URLs

urls.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.conf.urls import patterns, url, include
from rest_framework import routers
from .views import FruitViewSet

router = routers.DefaultRouter()
router.register(r'fruit', FruitViewSet)

urlpatterns = [
    url(r'^api/v1/', include(router.urls)),
]

With this configuration, a basic API interface is complete. Visiting http://localhost:8000/api/v1/ displays:

4.5 Permissions

1
2
3
4
5
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ]
}

4.6 Pagination Control

1
2
3
class YourView(BaseView):
    paginate_by = 10                 # 覆盖 settings 中的默认分页
    max_paginate_by = 100             # 限制最大分页大小

You can also determine the maximum page size dynamically:

1
2
3
4
5
class YouView(BaseView):
    ...
    def paginate_queryset(self, queryset):
        self.paginator.max_page_size = YOUR_PAGE_SIZE_LIMIT
        return super(YouView, self).paginate_queryset(queryset)

4.7 Handling Foreign Keys

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from rest_framework import serializers

class HospitalSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Hospital
        fields = '__all__'

class HospitalPicSerializer(serializers.HyperlinkedModelSerializer):
    hospital = HospitalSerializer()

    class Meta:
        model = HospitalPic
        fields = '__all__'

4.8 Rate Limiting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}

class ExampleView(APIView):
    throttle_classes = (UserRateThrottle,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

Limiting the frequency of API queries can be done per user, precise down to per day, per hour, or per minute.

4.9 Mixins

Django-rest-framework provides us with many ready-made mixins that can be used to quickly compose interfaces.

  • GenericAPIView provides the core functionality of a view
  • ListModelMixin provides the .list() method
  • CreateModelMixin provides the .create() method

In a View function, you can use them like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from .models import Fruit
from .serializers import FruitSerializer
from rest_framework import mixins
from rest_framework import generics

class FruitList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Fruit.objects.all()
    serializer_class = FruitSerializer

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

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

5. References


微信公众号
WRITTEN BY
微信公众号