Build a ToDo API in Django Rest Framework.

Shivansh Tiwari
13 min readAug 26, 2020

Building a REST API is super easy. In this tutorial, we will talk about steps that involve getting your first API up and running.

(This post is the part of a series where I am going to build a ToDo web application.)

Backend Tech: Django Rest Framework for API development.

Front-end Tech: HTML, CSS, JAVASCRIPT, AJAX.

[Want to see the Source code of the project? https://github.com/Shiv1202/ToDo-API]

◄Quick Summary: If you want to be able to read the API documentation and use them effectively, you’ll first need to understand the concept of REST API.►

THERE’S A HIGH CHANCE YOU CAME ACROSS THE TERM “REST API” if you’ve thought about getting data from another source on the internet, such as Twitter or Github.

What is a REST API?

Let’s say you’re trying to find images of nature on Unsplash.com. You open up Unsplash.com and type “Nature” in the search field, hit enter and you see list of various photos of nature. A REST API works in a similar way.

An API is an Application Programming Interface. It is a set of rules that allow programs to talk to each other. Developers create API on the server and allow the client/frontend to talk to it.

REST determines how the API is going to look like. It stands for “Representational State Transfer”. REST consists of a set of instructions that the developer has to follow when they are developing API.
One of these rules states that you should be able to get a piece of data when you click on a URL. Each URL is called a request while the data sent back to you is called a response.

Why REST API?

Before we get to the main development part, it’s worth considering why would you want to build an API. If someone had explained these basic concepts to me before I started, I would have been so much better off.

A REST API is a standardized way to provide data to other applications. These applications can then use the data however they want. Sometimes, APIs also offer a way for other applications to make changes to the data.

These are a few key options for a REST API request:

GET — The most common option, returns some data from the API based on the endpoint you visit and any parameters you provide.

POST — Creates a new record that gets appended to the database.

PUT — Looks for a record at the given URI you provided. If the exists, update the existing record. If not, create a new record.

DELETE — Deletes the record at the given URI

PATCH — Update the Individual field of the record.

NOTE: The main difference between the PUT and PATCH method is that the PUT method uses the request URI to supply a modified version of the requested resource which replaces the original version of the resource, whereas the PATCH method supplies a set of instructions to modify the resource.

Typically, an API is a window into a database. The API backend handles querying the database and formatting the response, what you receive is a static response, usually in JSON format, or whatever resource you requested.

The process of querying and converting tabular database values into JSON or another format is called SERIALIZATION. When you’re creating an API, the correct serialization of data is the major challenge.

Why Django Rest Framework?

Many frameworks allow you to easily build APIs for blog applications, but we will use only one — the Django REST framework. It’s convenient in many ways and offers the following advantages:

  1. Its Web-browsable API is a huge usability win for developers.
  2. Authentication policies include packages for OAuth1 and OAuth2.
  3. Great Serialization supports both ORM and non-ORM data sources.
  4. It has extensive documentation and great community support.

In a Django application, you define your structure of the database in the form of models using python. While you can write raw SQL queries, but for the most part, the Django ORM(Object Relation Mapper) handles all the hard and complicated database migrations and queries.

Think of the Django ORM like an accountant, pulling the information you need for you, so you don’t have to go get it yourself.

Main points for creating a REST API in Django.

So based on what we learn, let’s try to find out steps to creating a REST API.

  1. Set-Up Virtual Environment.
  2. Set-Up Django
  3. Create a model for the database that the Django ORM will manage.
  4. Set-Up Django Rest Framework
  5. Serialize the model data from step-3
  6. Create the URI endpoint to view the serialized data.

If it seems simple, that’s because it is. Let’s get to it!

1. Set-Up Virtual Environment

To start a new application first we have to set up a virtual environment, it helps to separate the various dependencies of the different projects.

Make a Directory on Desktop using the command prompt by running this command.

mkdir ToDo-API

Now move in that directory by running the following command.

cd ToDo-API

Install the virtualenv package

pip install virtualenv

Now, within the directory, create a Python virtual environment by typing:

virtualenv myenv

This will create a directory called myenv within ToDo-API directory.

Before you install the Python requirements for your project, activate the virtual environment
We can do this by typing:

source myenv/bin/activate

Our prompt should change to indicate that we are now operating within a Python virtual environment. It will look something like this:

(myenv) C:\<path to dirctory\>

2. Set-Up Django

Now, inside this virtual environment, we are going to install Django and other requirements.
We can install Django by typing:

pip install django

let’s create a new Django project:

django-admin startproject <project-name>

For this tutorial we keep <project-name> is todo-drf . Now, Directory structure something looks like this:

ToDo-API
|- todo-drf
|- myenv

And if we look inside the todo-drf folder, there’s everything we need to run a Django application.

ToDo-API
|- todo-drf
|- manage.py
|- todo-drf/*
|- myenv

Open this directory ToDo-API into your favorite IDE/Editor, for me, I open it with vs code.

After opening, switch to command prompt and make sure it works. Test run the Django server:

python manage.py runserverWatching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
May 17, 2019 - 16:09:28
Django version 2.2.1, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

go to http://127.0.0.1:8000 or localhost:8000 and you should see the Django welcome screen.

It works!!

A Django project is a collection of various apps, every app serves a different feature of our project.

2.1 Creating the first app

It is the best practice is to separate your Django project in different apps when you build something new.

So, let’s create the first app:

python manage.py startapp <app-name>

for this article let’s consider the app-name will be api.

After running the above command you will see the directory structure something like this:

ToDo-API
|- todo-drf/*
|- myenv/*
|- api/*

2.2 Register the api app in the todo-drf project settings file

We successfully created the first app but at this time Django is unaware of this app, so we need to tell Django to recognize this new app that we just created. For telling Django about the new app we are going to make changes inside the todo-drf/settings.py file.

Inside the todo-drf/settings.py file, we have to register the api app within Installed_Apps array.

INSTALLED_APPS = [
'api.apps.ApiConfig',
... # Leave all the other things same
]

2.3 Migrate the database

Remember that we discuss how Django allows us to define database using Python?

When we change/create something new inside models, we need to tell Django to make that changes to the main database by migrating those changes to the database. Now, the Django ORM is going to write all the SQL CREATE TABLE commands for us.

(For those who thinking about that, “We didn’t create any database!” You’re right! Django provides a simple SQLite database for us if we don’t specify differently.)

So, By running below command let’s migrate those initial setup:

python manage.py makemigrations
python manage.py migrate

2.4 Create Super User

One more before moving to the main API.

It would be great for us if we have access to the Django Admin Interface, for this let’s create THE ALL-POWERFUL SUPERUSER!!!

python manage.py createsuperuserUsername (leave blank to use 'Shivansh'): 
Email address:
shivansht9211@gmail.com
Password:
Password (again):
Superuser created successfully.

to verify it, start-up the Django development server, and navigate to localhost:8000/admin

python manage.py runserver

Now some of you might be thinking about who build this?

So, for your information that’s why Django is amazing because it provides a prebuild admin interface and User Model.

The Django admin interface helps us to view the database tables, edit objects, delete objects, and create new objects.

3. Create a model in the database for the ToDo application that the Django ORM will manage.

Now, we are going to make our first model!

we’ll build it in api/models.py file, so open up that file.

from django.db import models# Create your models here.class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False, blank=True, null=True)
objects = models.Manager()
def __str__(self):
return self.title

Here title is CharField where we can store Strings, and completed is BooleanField where we can only store True or False .

__str__ is a special method of python to determine what to print when it needs to print out an instance of the Task model.

3.1 Make Migrations

Whenever we define or change a model, we need to tell Django to reflect those changes into the database by migrating them.

python manage.py makemigrations
python manage.py migrate

3.2 Register Task model with admin panel

Remember, that admin interface for which we created superuser to access the admin panel. Now register Task model with admin so we can perform some basic operations.

Right now, Django admin doesn’t know the Task model, but with two lines of code we can tell the admin about Task .

Open api/admin.py and make it look like this.

from django.contrib import admin
from .models import Task
admin.site.register(Task)

Now run the Django server and navigate to localhost:8000/admin:

python manage.py runserver 
Our Task model is register!!

3.3 Create some new data records

We created our Task model but right now it is empty. Let’s create some tasks from the admin site to play around with the application.

Tasks in the database

4. Set-Up the Django Rest Framework

okay, till now we are ready with the database setup and some data inside the database to play around.

Now, it’s time to Set-Up the Django Rest Framework and serialize the data from our database via endpoints.

To do so let’s first install Django Rest Framework

pip install djangorestframework

Now, we need to tell the Django that we installed the REST Framework in todo-drf/settings.py.

INSTALLED_APPS = [
# All your installed apps stay the same
...
'rest_framework',
]

Now, we are ready with the REST Framework Set-Up.

5. Serialize the model from step-3

Now, let’s start to dive deep into the serialization part of the data. We need to tell the REST Framework about our Task model and how to serialize it.

To do so, let’s create a new file api/serializers.py.

In this new file we have to do a few things:

  1. import our models
  2. import serializer from REST Framework
  3. Create a new class that links the Task with its serializer.

Here is how it looks:

# serializers.pyfrom rest_framework import serializers

from .models import Task

class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'

that’s all we are completed with the serialization part.

6. Display the data

Now, we are only left to do is, bind the URLs and views to display the data!

6.1 Display API Overview

From the root URL of our API, we are going to display an overview of the API endpoint.

Change api/views.py:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import TaskSerializer
from .models import Task
"""
API Overview
"""
@api_view(['GET'])
def apiOverview(request):
api_urls = {
'List' : '/task-list/',
'Detail View' : '/task-detail/<str:pk>/',
'Create' : '/task-create/',
'Update' : '/task-update/<str:pk>/',
'Delete' : '/task-delete/<str:pk>/',
}
return Response(api_urls)

Now it’s time to add URLs

Site URLs

In Django URL are resolved at the project level first. So there’s a file in the todo-drf directory called urls.py

# todo-drf/urls.py
from django.contrib import admin
from django.urls import path, include

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

Now, we are telling Django to send every request related to api app into api/urls.py.

API URLs

Let’s modify our api/urls.py file by adding URLs endpoint.

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
]

Now start the server and navigate to localhost:8000/api/

python manage.py runserver
This is the root endpoint of our API

6.2 Views/Display all data

First, start with the api/views.py

To do so, we need to:

  1. Query the database for all Tasks.
  2. Pass that database query-set into the serializer we just created, so that it generates JSON format and render it.

api/views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import TaskSerializer
from .models import Task
"""
Below Function going to display all the tasks store in the data base.
"""

@api_view(['GET'])
def taskList(request):
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many = True)
return Response(serializer.data)

API URL

Now save the views.py file and it’s time to bind this function with URL endpoint in api/urls.py.

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
path('task-list/', views.taskList, name="task-list"),
]

After saving the file check whether the server is running or not, if it is running then visit localhost:8000/api/task-list/. Otherwise, start the server and visit the URL.

This list displays all the task store inside the database.

6.3 Views/Display single Task

We successfully displayed all Tasks from the database!!!

let’s return a single Task from the database depending upon the id of the task which is passed by the user in URL as a parameter.

api/views.py

"""
This Function going to display Detailed view of one perticuler task with the help of pk.
"""
@api_view(['GET'])
def taskDetail(request, pk):
tasks = Task.objects.get(id=pk)
serializer = TaskSerializer(tasks, many = False)
return Response(serializer.data)

API URL

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
path('task-list/', views.taskList, name="task-list"),
path('task-detail/<str:pk>/', views.taskDetail, name="task-Detail"),
]

Save both files which we edited, and visit localhost:8000/api/task-detail/<id>.

Display task which has id=1.

6.4 Views/Update an existing Task

Now we are able to display the list of Tasks and one single Task depending upon id input by the user in URL as a parameter.

Now let’s try to Update a single Task with respect to id enter by the user in URL.

api/views.py

@api_view(['POST'])
def taskUpdate(request, pk):
task = Task.objects.get(id = pk)
serializer = TaskSerializer(instance=task, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)

API URL

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
path('task-list/', views.taskList, name="task-list"),
path('task-detail/<str:pk>/', views.taskDetail, name="task-Detail"),
path('task-update/<str:pk>/', views.taskUpdate, name="task-update"),
]

Now, navigate to localhost:8000/api/task-update/<id>/.

we are updating the task with id=1.

6.5 Views/Creating a new Task

Our API is doing great, but now it’s time to make our API capable of creating a new Task.

For creating a new task we send a POST request from the URL endpoint to our API.

api/views.py

@api_view(['POST'])
def taskCreate(request):
serializer = TaskSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)

API URL

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
path('task-list/', views.taskList, name="task-list"),
path('task-detail/<str:pk>/', views.taskDetail, name="task-Detail"),
path('task-update/<str:pk>/', views.taskUpdate, name="task-update"),
path('task-create/', views.taskCreate, name="task-Create"),
]

After doing this navigate to localhost:8000/api/task-create/.

we are passing an object in JSON format.

6.6 Views/Delete existing Task by ID

Till now our API is doing good. Now we are left with only one operation to perform into the database.

Now, we have to delete an existing task depending upon ID passed by the user in the URL as a parameter.

api/views.py

@api_view(['DELETE'])
def taskDelete(request, pk):
task = Task.objects.get(id = pk)
task.delete()
return Response("Taks deleted successfully.")

Now we are ready to delete an existing task with respect to ID. Just one step away to the final completion, i.e. Setting delete URL.

API URL

from django.urls import path
from . import views
urlpatterns = [
path('', views.apiOverview, name="api-overview"),
path('task-list/', views.taskList, name="task-list"),
path('task-detail/<str:pk>/', views.taskDetail, name="task-Detail"),
path('task-update/<str:pk>/', views.taskUpdate, name="task-update"),
path('task-create/', views.taskCreate, name="task-Create"),
path('task-delete/', views.taskDelete, name="task-delete"),
]

visit localhost:8000/api/task-delete/<id> to delete any task.

Successfully delete a task with id = 1

YEP!!! You successfully developed your first REST API using the Django Rest Framework.

Having Trouble?

Here’s the source code of the ToDo-API, so you can check and verify your work.

Quick REST API with the Django Rest Framework

I hope you enjoyed this post and it helped you to build your first REST API using Django Rest Framework.

Of Course, APIs can do much more complicated work with multiple models intersection and endpoints with more complex queries. But you are on the way and on driving seat, go drive and build something cool, don’t forget to share your work with me.

If you get stuck, there’s a great community willing to help you find a great solution to your problem.

Share your work with me here:

https://www.linkedin.com/in/shiv1202/

https://www.instagram.com/productive_sst/

https://github.com/Shiv1202

connect with me

Thanks, Have fun building new APIs!

--

--

Shivansh Tiwari

Vue Js Developer, Nuxt Js Developer, Software Engineer