Building a restful api with Django REST framework tutorial

Building a restful api with Django REST framework tutorial

Share post:

Tutorial Code

You can find the code for this tutorial here:

What is RESTful API?

RESTful API (Representational State Transfer) is an architectural style for building web services that allows communication between different systems. RESTful APIs are designed to be simple and easy to use, allowing data to be transferred between different clients and servers.

A RESTful API works by using HTTP requests to GET, POST, PUT, and DELETE data. It uses a set of uniform resource identifiers (URIs) to identify resources and communicate with them.

Why we use RESTful API?

RESTful API is used to build scalable, efficient, and reliable web applications. Here are some reasons why we use RESTful API:

  • Simplicity: RESTful API uses a simple and lightweight architecture, making it easy to understand, implement, and maintain.

  • Scalability: RESTful API can handle a large number of client requests and can easily scale up or down depending on the traffic.

  • Flexibility: RESTful API is flexible and can work with different programming languages, platforms, and devices.

  • Statelessness: RESTful API does not store any client data or session information, making it easier to maintain and scale.

  • Security: RESTful API provides several security measures such as authentication, authorization, and encryption to secure data transmission and access.

  • Caching: RESTful API supports caching, which can improve performance and reduce server load.

  • Integration: RESTful API can be integrated with other systems and services, allowing for seamless communication and data exchange.

Overall, RESTful API is so popular because it offers a simple, flexible, and scalable architecture that can handle complex web applications and services.

The reason to have REST API in your project could be one of those: - Make a dashboard with a modern frontend framework, decoupled from your backend - Make a Command-Line Interface(CLI) tool to use your app - Integrate with other services, like Zapier, allowing people integrate with your app without coding - build additional backend services as part of your software, but decoupled from your main repo/codebase.

How to build REST API with Django?

Create a new Django project

Create a new Django project and start a new app called main.

mkdir rest_tutorial
cd rest_tutorial
python3 -m venv env
source env/bin/activate
pip install -U pip # update pip to the latest version
pip install django
pip install djangorestframework
django-admin startproject project .  # note the trailing '.' character

django-admin startapp main # create your main app

The project layout should look like this:

$ pwd

<some path>/rest_tutorial

$ find . -path './env' -prune -o -print # list all files and directories except `env`

Apply migrations

python migrate

Create a superuser in non-interactive mode.

DJANGO_SUPERUSER_PASSWORD=Hello123 python createsuperuser --email --username admin --noinput

I prefer using non-interactive mode everywhere, because it also teaches how to automate things when it comes to deployment and other type of tasks, there is no user to input any data.

Create models for our TODO app

Open main/ in your favorite editor and add these models.

from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class TaskList(models.Model):
    name = models.CharField(max_length=200)
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='task_lists')

    def __str__(self):

class Task(models.Model):
    title = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    task_list = models.ForeignKey(TaskList, on_delete=models.CASCADE, related_name='tasks')
    is_done = models.BooleanField(default=False)

    def __str__(self):
        return self.title

This is a pretty simple TODO list models. List belongs to a user, tasks belong to the list.

Task can be marked as done.

This simple structure already gives us enough to show in terms of REST framework features.

Go to project/ and add main and rest_framework to INSTALLED_APPS so it looks like this:

        'rest_framework',  # new
        'main',  # new

Now run python makemigrations to create migration files for our app and its models.

Then run python migrate to apply these migrations.

Register new models in the admin.

Create a file main/

from django.contrib import admin
from .models import TaskList, Task

class TaskListAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'owner'), TaskListAdmin)

class TaskAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'created_at', 'is_done', 'task_list'), TaskAdmin)

This code sets up the Django admin interface for the TaskList and Task models.

Two ModelAdmin classes, TaskListAdmin and TaskAdmin, are defined to customize the display of the TaskList and Task models in the Django admin interface. Each of these classes defines a list_display attribute that specifies which fields should be displayed in the list view for each model.

The method is then called twice to register the TaskList and Task models with their respective ModelAdmin classes. This makes the TaskList and Task models visible in the Django admin interface, and customizes their display based on the attributes defined in the corresponding ModelAdmin classes.

When this code is included in the file of a Django project, it sets up the necessary configuration for the Django admin interface to display the TaskList and Task models with the customizations defined in the TaskListAdmin and TaskAdmin classes, respectively. This allows admin users to easily view and manage the data stored in these models.

REST framework serializers

Create a file main/

Let's create serializers for the models we created.

from rest_framework import serializers
from . import models

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

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Task
        fields = ('id', 'title', 'created_at', 'is_done', 'task_list')

    def validate_task_list(self, value):
        if self.context['request'].user != value.owner:
            raise serializers.ValidationError('Invalid task list')
        return value

Let's talk for a second about what is serializers.

Serializer is a layer that helps to convert data into a representation and back while also validating the data.

Think of it as what Django forms do, but for API. At least that's what helped me to understand serializers initially.

In our example we have a validation for task_list during creation/update of the Task. TaskSerializer will check if the task_list specified for the Task belongs to the user who is sending the request.

If the user is different then ValidationError will be raise and the user will receive the 400 error.

REST framework CRUD views

We will use ModelViewSet for our TODO list app.

In Django, a ModelViewSet is a class that combines the functionality of a ViewSet with the abilities of Django's Model class. ModelViewSet provides a set of CRUD operations (Create, Read, Update, and Delete) that can be performed on a particular Django model.

When you define a ModelViewSet, it automatically generates a set of URLs for those CRUD operations. This can save you time and effort in setting up the URLs for your views.

ModelViewSet is part of Django Rest Framework (DRF), a powerful toolkit that allows you to easily build APIs in Django. It is particularly useful for building RESTful APIs, where you want to expose your data as a resource.

Using a ModelViewSet can save you time and effort in writing repetitive code for your views. For example, if you have a model called 'Product', you can create a ModelViewSet for it, which will provide you with a set of CRUD operations that can be performed on the 'Product' model. You can then customize these operations to suit your specific needs.

ModelViewSet is good to use when you are building APIs and you want to provide CRUD functionality on a particular Django model. It is also useful when you want to create a consistent set of URLs for your views, and when you want to reduce the amount of code you need to write.

In summary, you should use a ModelViewSet when you want to create a RESTful API for a particular Django model, and you want to reduce the amount of code you need to write for your views.

I prefer to decouple regular template rendering views from API views by putting them in separate files or modules.

Thus, I suggest you create a file main/ and let's create our API views in there.

from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet

from main.serializers import TaskListSerializer, TaskSerializer
from . import models

class TaskListViewSet(ModelViewSet):
    serializer_class = TaskListSerializer
    permission_classes = [IsAuthenticated, ]

    def get_queryset(self):
        return models.TaskList.objects.filter(owner=self.request.user)

    def perform_create(self, serializer):

class TaskViewSet(ModelViewSet):
    serializer_class = TaskSerializer
    permission_classes = [IsAuthenticated, ]

    def get_queryset(self):
        return models.Task.objects.filter(task_list__owner=self.request.user)

Viewsets TaskListViewSet and TaskViewSet are used to handle CRUD operations for TaskList and Task models respectively.

Both viewsets inherit from ModelViewSet, which provides default implementations for HTTP methods such as GET, POST, PUT, DELETE, etc.

TaskListViewSet specifies the TaskListSerializer as the serializer class to use for serializing and deserializing TaskList model instances. It overrides the get_queryset method to return a filtered queryset that only includes TaskList objects that belong to the current authenticated user. The perform_create method is also overridden to set the user field of the TaskList instance being created to the current authenticated user.

TaskViewSet specifies the TaskSerializer as the serializer class to use for serializing and deserializing Task model instances. It overrides the get_queryset method to return a filtered queryset that only includes Task objects that belong to a TaskList that belongs to the current authenticated user.

Django REST framework router and URLs

Now let's create URLs for our API.

Create a file main/

from rest_framework import routers

from .api import *

router = routers.DefaultRouter()
router.register(r'task-lists', TaskListViewSet, basename='task-lists')
router.register(r'tasks', TaskViewSet, basename='tasks')

urlpatterns = router.urls

The routers module is imported from the rest_framework package.

A DefaultRouter object is created and assigned to the router variable. The register method of the router object is then called twice to register two viewsets for their respective endpoints. The first endpoint is /task-lists and it maps to the TaskListViewSet viewset, while the second endpoint is /tasks and it maps to the TaskViewSet viewset.

Finally, the urlpatterns variable is set to the router.urls attribute, which is a list of URL patterns that correspond to the registered viewsets.

When this code is included in the file of a Django project, it sets up the necessary routing for the two viewsets to handle HTTP requests to the specified API endpoints. For example, a GET request to /task-lists would be handled by the TaskListViewSet's list method, while a POST request to /tasks would be handled by the TaskViewSet's create method.

Now open the project/ and let's include our API routes into the project's URLs.

from django.contrib import admin
from django.urls import path, include  # new: added include function

urlpatterns = [
    path('', include('main.urls')),  # new

Testing our API

Let's run our app.

python runserver

Open our app in browser:

Django REST Framework Index Page

You see two links to our end points.

First, you need to authenticate, in order to do that let's visit the admin URL and do it there.

Use credentials we used earlier: "admin", "Hello123"

Visit endpoint:

Create a list.

After submitting the form you will see that list was created

Visit endpoint for task lists again and see that we have a list:

Now if you go to the admin, to Task Lists you will see that the object was created with the owner field set to "admin".

Let's create a task.

Head over to the tasks endpoint.

Fill in the form and create a task.

After clicking "POST" you will see that the Task record was created.


Stop wasting time manually
deploying your apps!

Try our application deployment tool that allows you to set up servers automatically, deploy apps from git, manage Postgres backups and cron tasks.

  • Use a server from any cloud provider
  • Setup is done automatically
  • Deploy Django, Flask, FastAPI, Node apps
  • Unlimited number of databases
  • Custom domains and HTTPS
  • Focus on apps, we take care of deployments

As developers ourselves, we hated wasting time writing configuration files for web servers, CI pipelines and managing apps via SSH – so we built the system that we always wanted.

Appliku takes care of everything you need to deploy, run and manage your apps, while you can still do customized configuration if you choose to.

Try it with a free plan and see for yourself.

Start Free
Simple 5-minute setup – No credit card required
Share post: