That’s when I decided to analyze the thought process of a developer who has a project that is more or less ready and now wants to add a REST API to it.

Usually, he or she will have a look at this tutorial. Once the developer reads it and gets the basics, it’s time to implement its content in the application. In most cases, we want to have CRUD, and then some additional options for filtering available objects, and then some other functional endpoints like statistics or a search engine.

And suddenly, it dawned on me:

The DRF tutorial is written in reverse order, and that’s where the problem comes from. Have a look at it, and you’ll see that it attempts to show low-level versatility instead of meeting the expectations of developers and showing high-level acronyms instead.

When we read the tutorial, we first learn about the details of views, serializers, and, only at the very end, about ViewSets – a wonderfully compact way for binding everything into a neat, clear and manageable whole. But most developers never get to this place because they have already built a relatively functional API and decided to abandon the tutorial in favor of the API Guide, searching for ways of implementing their project requirements.

This article is the first one in a series where I plan to show you Django REST Framework from the general to detailed overview and help you avoid reinventing the wheel.

Follow this series, and you’ll get clear and highly manageable code that won’t bring you shame when you show or transfer it to others.

Part 1 – CRUD

If you’re reading this, you probably already have at least the application’s wireframe, and you want to add a REST API to enable basic operations on objects such as Create, Retrieve, Update and Delete (CRUD). That’s what we will do in this article.

For starters, let’s prepare an example application for managing things we lend to our friends. Then, we need to install Django REST Framework.

; cd your project’s directory and activate its virtualenv
$ ./manage.py startapp rental
$ pip install djangorestframework

 

Next, we need to modify the INSTALLED_APPS parameter in settings.py file.

settings.py

1
2
3
4
5
6
INSTALLED_APPS = [
# previous apps

'rental',
'rest_framework',
]

 

rental/models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.db import models

class Friend(models.Model):
name = models.CharField(max_length=100)

class Belonging(models.Model):
name = models.CharField(max_length=100)

class Borrowed(models.Model):
what = models.ForeignKey(Belonging, on_delete=models.CASCADE)
to_who = models.ForeignKey(Friend, on_delete=models.CASCADE)
when = models.DateTimeField(auto_now_add=True)
returned = models.DateTimeField(null=True, blank=True)

 

To make our objects available through the API, we need to perform a serialization – reflect the data contained in the object textually. The default format here is JSON, although DRF allows serialization to XML or YAML. The reverse process is called deserialization.

Both processes are defined in objects referred to as serializers. DRF offers developers with a convenient class to create serializers for Django models easily, so we have to provide only some basic information such as the model that will be served in the serializer and the fields to which we want to give access.

rental/serializers.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from rest_framework import serializers
from . import models

class FriendSerializer(serializers.ModelSerializer):
class Meta:
model = models.Friend
fields = ('id', 'name')

class BelongingSerializer(serializers.ModelSerializer):
class Meta:
model = models.Belonging
fields = ('id', 'name')

class BorrowedSerializer(serializers.ModelSerializer):
class Meta:
model = models.Borrowed
fields = ('id', 'what', 'to_who', 'when', 'returned')

 

Now we need to create views that will handle each of the operations we want to perform on our objects.

Consider for a moment their names and how to combine them with methods available in the HTTP standard.

Create – that one is rather straightforward. Standard support for it comes from the HTTP POST method. Because we’re creating a set element here (in particular, the object’s ID will be only determined now), we treat this method as an operation on the list: creating an element.

Retrieve – we have two options here: we can download a list of objects of a given type (list) or one specific object (retrieve). In both cases, GET will be the adequate HTTP method.

Update – There are two HTTP methods available here: PUT and PATCH. The difference between them is that according to its definition, PUT requires all attributes of the object – including those that have not changed. PATCH, on the other hand, allows entering only those fields that have actually changed, which is why it’s more popular. Using the PUT or PATCH method to update multiple objects is rare and DRF only supports updating single object in its default CRUD.

Delete – this deletes one or many objects. The HTTP method here will be DELETE. In practice, for security reasons, it’s usually not possible to remove several objects at the same time and again, DRF only supports this operation on single objects in its default CRUD. .

Let’s summarize all of the above:

Operation HTTP method endpoint type
Create POST list
Retrieve many GET list
Retrieve one GET detail
Update PUT / PATCH detail
Delete DELETE detail

 

To support such a set of operations, DRF provides a handy tool – ViewSet. It takes the idea behind the standard class-based views from Django to a higher level. What it does is packing the above set into one class with the automatic creation of appropriate URL paths.

So let’s see how that looks like in practice:

To start, let’s create a ViewSet that will support our models. DRF provides the ModelViewSet thanks to which the required amount of code is reduced to the minimum:

rental/api_views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from rest_framework import viewsets
from . import models
from . import serializers

class FriendViewset(viewsets.ModelViewSet):
queryset = models.Friend.objects.all()
serializer_class = serializers.FriendSerializer

class BelongingViewset(viewset.ModelViewSet):
queryset = models.Belonging.objects.all()
serializer_class = serializers.BelongingSerializer

class BorrowedViewset(viewsets.ModelViewSet):
queryset = models.Borrowed.objects.all()
serializer_class = serializers.BorrowedSerializer

 

Then there’s the last part – connecting all this to the URL tree of our project. And here we get a very convenient tool as well – routers. DRF provides two of the most important classes that differ only in that one of them shows the API structure when downloading / (root), and the other doesn’t.

Our viewsets will be hooked up as follows:

api.py (global, next to settings.py)

1
2
3
4
5
6
7
from rest_framework import routers
from core import views as myapp_views

router = routers.DefaultRouter()
router.register(r'friends', myapp_views.FriendViewset)
router.register(r'belongings', myapp_views.BelongingViewset)
router.register(r'borrowings', myapp_views.BorrowedViewset)

 

urls.py (global)

1
2
3
4
5
6
7
8
from django.urls import include, path
from django.contrib import admin
from .api import router

urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
]

 

Let’s test the API we created.

$ ./manage.py makemigrations
$ ./manage.py migrate
$ ./manage.py runserver

 

Open this address in your browser (in standard configuration): https://127.0.0.1:8000/api/v1/

DRF automatically creates views that allow performing API queries from the browser level:

Experiment and check the effects in the django-admin panel.

Conclusion

At this point, we receive a ready API that supports CRUD for our models. Please note that we don’t have any security against unauthorized access here yet.

We will deal with the user login and registration process in the next article in this series.

Dominik Kozaczko
Dominik
Backend Engineer

Since 2005 Dominik professionally does what he hoped for since childhood - he is a programmer AND a teacher. He specializes mostly in backend development and training junior devs.

LOAD COMMENTS

arrow

Join our newsletter.

Scroll to bottom

Hi there, we use cookies to provide you with an amazing experience on our site. If you continue without changing the settings, we'll assume that you're happy to receive all cookies on the Sunscrapers website. You can change your cookie settings at any time.

Learn more