Starting with django-rest-framework

Hernán Tylim
Django Musings
Published in
4 min readApr 17, 2016

Django-Rest-Framework doc here.

Let’s say that you want to create a REST API and you want to use rest_framework, here is what you need to know to start using it right away (BTW you can also read their official tutorial, here).

Configuration

All rest_framework configuration goes into a dictionary in your settings.py file called REST_FRAMEWORK.

example:

REST_FRAMEWORK = {
‘DEFAULT_PERMISSION_CLASSES’:
[‘rest_framework.permissions.IsAdminUser’],
‘PAGE_SIZE’: 10
}

Serializers

Serializers are the classes responsible for taking, lets say, Model instances, and serializing them into, let’s say, a JSON representation.

Serializers work both ways, from Model to JSON and from JSON to Model.

So your class needs to have a Serializer for each ‘API object’ that you will be representing within your API. Typically you put these serializers in a serializers.py module.

A Serializer looks like this:

from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False,
allow_blank=True, max_length=100)
author = serializers.CharField()
def create(self, validated_data):
“””
Create and return a new `Book` instance, given the
validated data.
“””
return Book.objects.create(**validated_data)
def update(self, instance, validated_data):
“””
Update and return an existing `Book` instance,
given the validated data.
“””
instance.title = validated_data.get(‘title’, instance.title)
instance.code = validated_data.get(‘code’, instance.code)
instance.save()
return instance

It is much alike declaring a Form in Django (or a Model). You specify the fields of your API objects as in a form.

The methods create and update let’s you code how the transformation from ‘API object’ to ‘YOUR DOMAIN object’ occurs.

Now. The one above is the complex way of using serializers, if you are handling Model instances you can just do it this way:

class BookSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Book
fields = (‘url’, ‘title’, ‘author')

The class HyperlinkedModelSerializer (which extends ModelSerializer) will automatically read the fields from your model, and now how to create and update their instances.

In the Meta subclass you specify the actual model that this serializer needs to work with, and the fields that will be included in the representation of the object.

HyperlinkedModelSerializer does something more. That field ‘url’ is the url that will act as an ID for the object, this is better than just using the plain ‘pk’ of the model instances. But if you don’t want that you can just use ModelSerializer.

Requests and Responses

rest_framework provides its own Request and Response objects to aid you in building your Views (which will be your REST API endpoints)

The Request object will for instance include a .data dictionary with the data of the request, no more .GET, .POST or .PUT dictionaries.

The Response object will accept ‘unrendered data’ (your django’s object) and know how to render it in whatever type of presentation if needs to be rendered (as you will see you can select the type of presentation to use)

Views

Your REST API endpoints are Views in your django’s app. For building this View rest_framework provides many facilities.

If you want to use a function-based view, you can use the @api_view decorator.

For class-based views you have the APIView base class.

These wrappers will take care of translating Django’s own Request object into rest_framework’s one, as well as taking Response object as return value

They will also handle some errors by themselves (for instance they will know to answer METHOD_NOT_ALLOWED if you didn’t declare an operation)

Here an example for @api_view:

from django.http import HttpResponse
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
@api_view([‘GET’, ‘POST’])
def snippet_list(request):
if request.method == ‘GET’:
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
elif request.method == ‘POST’:
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,
status=status.HTTP_201_CREATED)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)

Here is a view that will check the type of operation, read the data from the serializer and do whatever it needs to do. This is all too much work. rest_framework provides you with class-based views that already do all of this automatically so you can write views in 3 lines of codes:

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer

Check generics to see what types of APIView the framework provides.

URLConf

Now that we have our Views coded we need to add our url mappings in the urls.py of our app. You can do it like this:

from django.conf.urls import url
from snippets import views
urlpatterns = [
url(r’^snippets/$’, views.snippet_list),
url(r’^snippets/(?P<pk>[0–9]+)/$’, views.snippet_detail),
]

Authentication

For implementing this we need is to specify what type of access each View has and that can be done very easily overriding permission_classes field:

from django.contrib.auth.models import Userfrom rest_framework import generics
from rest_framework import permissions
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
class SnippetList(generics.ListCreateAPIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer

The permissions.IsAuthenticatedOrReadOnly permission scheme will gave access read-only for all the SAFE operations (GET, HEAD, OPTIONS, …), and access to the other operations only for authenticated users.

Here rest_framework will work alongside django’s user authentication system.

There are other types of permission schemes, but if you want to do something custom you just need to add the class in the permission_classes field, and implement the class with something like this:

from rest_framework import permissionsclass IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user

in this example obj.owner would point to a field on our model and is being compared the user specified in the in the Request session.

--

--