How to build an API using Django Rest Framework

Django REST Framework is a powerful and flexible toolkit for building web APIs

The purpose of this article is to help you learn new staff and practicies while creating new things. The goal is to create a To-do List application where we can store our thoughts about things we want to do for today, tomorrow or someday.

Here are some reasons why to use  DRF

- It is used and trusted by internationally recognised companies including Mozilla, Red Hat, Heroku, and Eventbrite.
- It's Customizable all the way down
- The huge usability of the web browsable API
- Serialization that supports both ORM and non-ORM data sources
- Extensive documentation and huge community support

You can read more about the Django REST Framework here

What we will need

For the Django REST Framework we need Python and Django Web Framework
Let's go ahead and install  the requirements

First things First!
Create a folder for you project, I will name mine 'todolist'

$ mkdir todolist

Then create a virtual environment for this project using virtualenv and Python 3.
The use of virtual environment is strongly recommended

 $ virtualenv -p /usr/local/bin/python3 venv

Now that we have created our environment there is one last thing we need to do before any installation attempt. Activate it

$ source venv/bin/activate

You'll see your prompt with a (venv) prefix, like this:

(venv) pycat@ghost:~/workspace/APIs/todolist$

Now we are ready ti install the dependencies. Lets' install Django using pip :

$ pip install  Django

And then finaly create the our project. You can give a whatever name to your project

$ django-admin startproject todorest .

* dont forget the dot at the end

Now Django already structered our basic project file witch looks like this

│   ├──
│   ├──
│   ├──
│   └──

There is one more requirement we need to install - DRF

$ pip install djangorestframework

Include DRF into settings file:

# Application definition



Time to create the REST API app

We will create a new django application with the name app. Yeah, that's right
the REST API will get started as a simple django application

$ ./ startapp api


Include api into settings file:

# Application definition



Lets Rock'n Roll

"Do nothing until you have a test"

The best way to do code testing is by using Test-Driven Development (TDD). This is how it works:

Write a test. – The test will flesh out some functionality in your app

Then, run the test – The test should fail, since there's no code to make it pass.

Write the code – To make the test pass

Run the test – If it passes, you are confident that the code you've written meets the test requirements

Refactor code – Remove duplication, prune large objects and make the code more readable. Re-run the tests every time you refactor the code

Repeat – That's it!


Open the file inside the appi directory and add the following code.
The following code imports the testcase from django.test library and tests
whether the the Model TodoList can create a list. It is a simple test:


from django.test import TestCase
from .models import  TodoList

class ModelTestCase(TestCase):
    # lets define a test suit for the todolist model

    def setUp(self):
        # define the test client and other test
        self.todolist_name = "Goto the supermarket"
        self.todolist = TodoList(name="todolist_name")

    def test_model_can_create_a_list(self):
        objects_count = TodoList.objects.count()
        objects_new_count = TodoList.objects.count()
        self.assertNotEqual(objects_count, objects_new_count)


We need to define the Model before we run the above test. Open the file and add the folowing code:

from django.db import models

# Create your models here.

class TodoList(models.Model):

Now it is time to run the tests.

(venv) pycat@ghost:~/workspace/APIs/todolist$ ./ test


After that you will get nothing but errors but don't worry, that;s excactly the point of Test Driven Development

We will build the Model code while we're trying to solve the test errors ;)

Edit the file and add the following:

from django.db import models

# Create your models here.

class TodoList(models.Model):
    name = models.CharField(max_length=255, blank=False, unique=True)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    def __str__(self):
        return "{}".format(



$ ./ makemigrations
$ ./ migrate


And run the test again:

$./ tests

Bingo! This test passes!!!


Serialization Time

Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data. You can read more about DRF Serializers here

The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields. Create a file and fill in the following code:

from rest_framework import serializers
from .models import TodoList

class TodoListSerializer(serializers.ModelSerializer):

    class Meta:
        model = TodoList
        fields = ('id', 'name', 'created', 'modified')
        read_only_fields = ('created', 'modified')


That's it. This serializer maps the Model instance into JSON format!


Building the Views

First write the tests. Writing the tests seems scary at first but not if toy work according to strategy. How do you know what to test? Just think about and make a list of things that you want to implement. For the views we need to handle the follwing:

♦ Create a todo list –  POST request

♦ Read a todo list –  GET request

♦ Update a todo list –  PUT request

♦ Delete a todo list –  DELETE request

We're going now to write the test basing to the above list.

Add the code below in your :

# test views imports
from rest_framework.test import APIClient
from rest_framework import status
from django.core.urlresolvers import reverse

# define the ViewTestCase testsuite right after the ModelTestCase
class ViewTestCase(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.todolist_data = {'name': 'Go to the supermarket'}
        self.response =

    def test_api_can_create_list(self):
        self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)

If you go ahaid you'll se tha running the test fails. That's ok because we havent implement yet the URconf and the views that satisfy this request. So lets implement them

Edit the

from django.shortcuts import render
from rest_framework import generics

from .serializers import TodoListSerializer
from .models import TodoList

# Create your views here.
class CreateView(generics.ListCreateAPIView):
    qyeryset = TodoList.objects.all()
    serializer_class = TodoListSerializer

    def create_performance(self,serializer):
        # save the POST data when user creates a new todo list

 We make use of the ListCreateAPIVIew witch is a DRF class-based view that provides GET and POST handlers. One of the key benefits of class-based views is the way they allow you to compose bits of reusable behavior. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns. You can read more about DRF Generic Views here.


Time For URL Configuration

URLs are the interface of our API to the outside world. A clean and usable URL scheme is an important detail in a high-quality Wev Application. With DRF we can design URLs however we want with no framework limitations.

We will create a file on the api directory. This is where we define our url patterns.

from django.conf.urls import url, include
from .views import CreateView

urlpatterns = {
    url(r'^todolist/$', CreateView.as_view(), name="create")


We'll also have to include our api.urls to the main apps urls so tha it points to our
API. Go to the todorest folder edit the  Our now should look
like this:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [

    # finaly we add the url to the main app's so that it point to the APIapp
    url(r'^', include('api.urls')),


Our tests should be working now.

(venv) pycat@ghost:~/workspace/APIs/todolist$ ./ test

Creating test database for alias 'default'...



Ran 2 tests in 0.017s

Destroying test database for alias 'default'...


Spin up the server!

$ ./ runserver

We assume here that we have allready activated a virtualenv with python3. It's the same typing:

$ python3 runserver

If we see the following console means that everything goes well and the app is running smoothly

(venv) pycat@ghost:~/workspace/APIs/todolist$ ./ runserver
Performing system checks...

System check identified no issues (0 silenced).
April 04, 2017 - 09:33:08
Django version 1.10.6, using settings 'todorest.settings'
Starting development server at
Quit the server with CONTROL-C.

Now let's open the todo list url on the browser to check out how it works. Type this or click it to open  http://localhost:8000/todolist/

If everything has gone well you should see something similar to this:

Time check how the api works. Go ahead and insert a Todo List. Then you should see something like this:

GET, UPDATE and DELETE actions

Test goes First as usual:

def test_api_can_get_list(self):
    todolist = TodoList.objects.all()
    response = self.client.get(
        kwargs = {'pk':}, format="json"

    self.assertEqual(response.status_code, status.HTTP_200_OK)
    self.assertContains(response, todolist)

def test_api_can_update_list(self):
    todolist = TodoList.objects.get()
    update_list = {'name': 'New list item name'}
    response = self.client.put(
        reverse('details', kwargs={'pk':}),
        update_list, format='json'
    self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_api_can_delete(self):
    todolist = TodoList.objects.get()
    response = self.client.delete(
        reverse('details', kwargs={'pk':}),

    self.assertEquals(response.status_code, status.HTTP_204_NO_CONTENT)

Running this tests we get 3 fails. That's absolute normal. We need to write some code in order get rid of those test errors. If we pay some attention on the erro logging we will find out that threre are some view problems and also some url resorvers that need configuration.

First we will implement our details view using RetrieveUpdateDestroyAPIView a Generic view witch is used for read-write-delete endpoints to represent a single model instance. It Provides GET, PUT, PATCH and DELETE method handlers. You can read more in the documentation

Add the following code in your

class DetailsView(generics.RetrieveUpdateDestroyAPIView):

    queryset = TodoList.objects.all()
    serializer_class = TodoListSerializer


Now add the url configuration for this view. Our now should look like this:


from django.conf.urls import url, include

from .views import CreateView DetailsView

urlpatterns = {
    url(r'^todolist/$', CreateView.as_view(), name="create")

    url(r'^todolist/(?P<pk>[0-9]+)/$',DetailsView.as_view(), name="details"),


That's It!!


Why should I use TDD?

In software development, testing is paramount. So why should I do it, you ask?

Tests have a short feedback loop, enabling you and your team to learn faster and adjust

Less time is spent debugging, allowing you to spend more time writing code

Tests act as documentation for your code!

They improve code quality while reducing bugs

After refactoring code, your tests will tell you whether the change has broken previously working code, and...

Tests are documentation Ever suffered from not knowing how a newly acquired and quite complex system works? Well-written unit tests show how the individual classes work together to achieve one or more business tasks. Analysing that code permitts new developers figure out the internal workings of the system quickly.

Unit tests help you to get zoned. Programmers and HR managers dream of the concept of the zone – a mental state where effectiveness reaches the highest possible level. Getting into it tends to require some introductory work, which is subject related but not particularly complex. Coding unit tests is an ideal example for such ‘menial tasks

It prevents catastrophic errors If you release an application where a crucial feature doesn’t work it can result in huge monetal losses. A reliable set of tests mitigates this by ensuring that no products get shippeThis is how it works:

Testing Is Fun. If you thrive on challenges, then testing is a lot of fun.


Find me