Create a django todo app using django-rest-framework.

In this tutorial, you will be learning how to create a todo app using Django/Python and drf (django rest framework).

Let's get started:

We have to install some tools:

I will assume you already have pip and python installed.

pip install pipenv - to install a virtual environment.
pipenv shell - creates/springs up a virtual environment for your app.
pipenv install django~=3.1.0 - to install the django package.
pipenv install djangorestframework~=3.11 - to install the django rest framework.
pipenv install psycopg2~=2.8.5- for database connection.

Run django-admin startproject <name of app> - creates a new app folder with its config/settings/details.

I will assume that you have postgres installed, create a new database called: todoapp and add the following piece of code to the .env file.


Then in the settings file,

Add the following piece of code for database connectivity:

import os - at the top of the file.

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - to build the path.

  • replace the database configuration with the following piece of code to enable us use postgres.
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': os.getenv('db_name'),
        'PASSWORD': os.getenv('db_password'),
        'USER': os.getenv('db_user'),
        'PORT': '5432',
        'HOST': 'localhost'

add rest_framework and todoapp - to the INSTALLED_APPS right under the other ones there.


cd into the newly created app/folder(todoapp) and run

  • python makemigrations todoapp to migrate and propagate new changes.
  • python migrate todoapp to migrate files into the database
  • python runserver to start up the server. You can view this in your browser using the url.

In the todoapp folder, where the settings file is, create a new file called and add the following code:

from django.db import models

class NoteModel(models.Model):

    title = models.CharField(max_length=100)
    description = models.CharField(max_length=200)
    tags = models.CharField(max_length=300)

    def __str__(self):
        return self.title


create another file called and add the following code:

from django.contrib.postgres.fields import ArrayField
from rest_framework import serializers
from .models import NoteModel

class NoteSerializer(serializers.ModelSerializer):

    title = serializers.CharField(max_length=100)
    description = serializers.CharField(max_length=200)
    tags = ArrayField(
        serializers.CharField(max_length=300), default=list)

    class Meta:
        model = NoteModel
        fields = ['title', 'description', 'tags']


  • the ArrayField is imported to enable us to add an array of items(tags) to the database.
  • serializers are imported from django rest framework.
  • also, the created model is imported.
  • we declare serializers that can help us to serialize data.

create another file called and add the following code:

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import NoteModel
from .serializers import NoteSerializer

class NoteView(APIView):

    Create a new note

    def post(self, request):
        serializer = NoteSerializer(
        if serializer.is_valid():
            return Response(, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    Get all notes

    def get(self, request):
        notes = NoteModel.objects.all()
        serializer = NoteSerializer(notes, many=True)
        return Response(, status=status.HTTP_200_OK)

class NoteDetailView(APIView):

    Get a note

    def get_object(self, pk):
            return NoteModel.objects.get(pk=pk)
        except NoteModel.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        note = self.get_object(pk)
        serializer = NoteSerializer(note)
        return Response(

    Update a note

    def put(self, request, pk, format=None):
        note = self.get_object(pk)
        serializer = NoteSerializer(note,
        if serializer.is_valid():
            return Response(
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)    

    Delete a note

    def delete(self, request, pk, format=None):
        note = self.get_object(pk)
        return Response(status=status.HTTP_204_NO_CONTENT)


  • we are making use of the django rest framework's class-based views.
  • the created models and serializers are created.
  • two classes are created called NoteView and NoteDetailView.
  • for the class NoteView, two methods are created for post to create a new note and get to get all notes.
  • then for the class NoteDetailView, three methods are created forput to update a note, delete to delete a note and get to get a single note.

Read more about the methods on the official docs:

We have to create URLs for the created methods, add the following code:

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import NoteView, NoteDetailView

urlpatterns = [
    path('notes', NoteView.as_view()),
    path('note/<int:pk>', NoteDetailView.as_view()),

urlpatterns = format_suffix_patterns(urlpatterns)

Run python runserver to start your server and test the endpoints.

For the code repo:

That marks the end of this tutorial.