Building an API with Django REST Framework

January 03, 2026
30 min read
Lalit Mahato
Building an API with Django REST Framework

Building an API with Django REST Framework

This tutorial assumes you have already created your Django project and have the Task model defined in your models.py. We will now turn that model into a fully functional API using the Django REST Framework (DRF).

Step 1: Install and Configure DRF

First, we need to install the package. Open your terminal and run:

pip install djangorestframework

Next, tell your Django project that you want to use this library. Open your project's settings.py file and add 'rest_framework' to the INSTALLED_APPS list:

Start app api:

python3 manage.py startapp api

Next, tell your Django project that you want to use this library. Open your project's settings.py file and add 'rest_framework' to the INSTALLED_APPS list:

# settings.py

INSTALLED_APPS = [
    ...
    'django.contrib.staticfiles',
    'rest_framework', # Add this line
    'api',  # Ensure your app is also listed
]

Step 2: Create a Serializer

To send data over the internet (usually as JSON), we need to translate our Python database objects into a format that can be easily rendered. This process is called serialization.

Create a new file named serializers.py inside your app directory (the same folder where models.py lives).

# serializers.py

from rest_framework import serializers
from .models import Task

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        # We include all fields from your model
        fields = ['id', 'title', 'completed', 'created_at', 'creator', 'modifier', 'assign_to']

Step 3: Create the View

Now we need to define the logic for our API. We will use a ViewSet. A ViewSet is a special type of class-based view that automatically provides implementations for standard actions like:

  • List (GET all tasks)

  • Create (POST a new task)

  • Retrieve (GET a single task)

  • Update (PUT/PATCH a task)

  • Destroy (DELETE a task)

Open your views.py file and add the following:

# views.py

from rest_framework import viewsets
from .models import Task
from .serializers import TaskSerializer

class TaskViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows tasks to be viewed or edited.
    """
    queryset = Task.objects.all().order_by('-created_at')
    serializer_class = TaskSerializer

Step 4: Configure URLs

Finally, we need to map a URL to our view so users can access the API. DRF provides a Router to handle this automatically.

Create a urls.py file in your app directory (if it doesn't exist) or modify the existing one:

# urls.py

from django.urls import path, include
from .views import TaskViewSet
from rest_framework import routers

# Create a router and register our viewset with it.
router = routers.SimpleRouter()
router.register(r"", TaskViewSet, basename="task_viewset")
urlpatterns = []
urlpatterns += router.urls

Don't forget: If this is a new app, ensure this urls.py is included in your main project's urls.py.


Step 5: Test the API

Now, run your server:

python manage.py runserver

Summary of What We Built

Component Purpose
Serializer Converts your Task model instances into JSON data.
ViewSet Handles the logic (Creating, Reading, Updating, Deleting).
Router Automatically generates the URL paths for your API.

 

Generic API Views.

While ModelViewSet (from the previous step) is great for quick setups, developers often prefer Generic Views because they offer more control. For example, you might want a "Read-Only" endpoint that only allows Listing and Retrieving, but not Creating or Deleting.

Using the specific classes (ListAPIView, CreateAPIView, etc.) allows you to build exactly what you need.


Step 1: Update views.py

Replace the content of your views.py with the following code. We are importing the generic views from rest_framework.generics and creating a separate class for each action.

# views.py

from rest_framework import generics
from .models import Task
from .serializers import TaskSerializer

# 1. ListAPIView: Used for read-only endpoints to represent a collection of model instances.
class TaskListAPIView(generics.ListAPIView):
    queryset = Task.objects.all().order_by('-created_at')
    serializer_class = TaskSerializer

# 2. CreateAPIView: Used for create-only endpoints.
class TaskCreateAPIView(generics.CreateAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

# 3. RetrieveAPIView: Used for read-only endpoints to represent a single model instance.
class TaskRetrieveAPIView(generics.RetrieveAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer
    # Note: We don't need to filter by ID manually; the view handles lookup_field='pk' by default.

# 4. UpdateAPIView: Used for update-only endpoints for a single model instance.
class TaskUpdateAPIView(generics.UpdateAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

# 5. DestroyAPIView: Used for delete-only endpoints for a single model instance.
class TaskDestroyAPIView(generics.DestroyAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

Step 2: Update urls.py

Unlike ViewSets, Generic Views cannot be used with a Router. We must define explicit URL patterns. This gives you exact control over your URL structure.

Update your urls.py:

# urls.py

from django.urls import path
from .views import (
    TaskListAPIView,
    TaskCreateAPIView,
    TaskRetrieveAPIView,
    TaskUpdateAPIView,
    TaskDestroyAPIView
)

urlpatterns = [
    # URLs for the collection (List and Create)
    path('tasks/', TaskListAPIView.as_view(), name='task-list'),
    path('tasks/create/', TaskCreateAPIView.as_view(), name='task-create'),

    # URLs for individual items (Retrieve, Update, Destroy)
    # We must pass the Primary Key (<int:pk>) so the view knows which task to act on.
    path('tasks/<int:pk>/', TaskRetrieveAPIView.as_view(), name='task-detail'),
    path('tasks/<int:pk>/update/', TaskUpdateAPIView.as_view(), name='task-update'),
    path('tasks/<int:pk>/delete/', TaskDestroyAPIView.as_view(), name='task-delete'),
]

Step 3: Comparison Table

To help you understand when to use which class, here is a quick reference:

Class HTTP Method Purpose
ListAPIView GET Returns an array/list of all tasks.
CreateAPIView POST Adds a new task to the database.
RetrieveAPIView GET Returns the data for a single task (requires ID).
UpdateAPIView PUT / PATCH Modifies an existing task (requires ID).
DestroyAPIView DELETE Removes a task from the database (requires ID).

Step 4: A Cleaner Approach (Best Practice)

While the method above works perfectly, having 5 separate views for one model can get cluttered. In production, Django REST Framework provides combined generic views to group common patterns.

You can often condense the code above into just two views:

  1. ListCreateAPIView: Handles both listing (GET) and creating (POST).

  2. RetrieveUpdateDestroyAPIView: Handles reading (GET), updating (PUT), and deleting (DELETE) a single item.

Here is how you would typically write this in a real project:

# views.py (Optimized version)

from rest_framework import generics
from .models import Task
from .serializers import TaskSerializer

class TaskListCreateView(generics.ListCreateAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

class TaskDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

This reduces your URL configuration to just two lines as well, while keeping the functionality identical to the 5 separate classes.

 

Lalit Mahato

Lalit Mahato

Software Engineer | Machine Learning Enthusiast

Innovative and results-driven software developer with 5+ years of experience in designing, developing, and deploying high-quality software solutions. Proficient in various programming languages and technologies, with a keen interest in …

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment

Search

Categories

Related Posts

Mastering Custom Pagination in Django Rest Framework
Mastering Custom Pagination in Django Rest Framework

Jan 08, 2026

Read More
Mastering Token Authentication with Django Rest Framework & Swagger
Mastering Token Authentication with Django Rest Framework & Swagger

Jan 08, 2026

Read More
Data Validation in Django REST Framework (DRF)
Data Validation in Django REST Framework (DRF)

Jan 07, 2026

Read More