Python

Django REST API Tutorial for Beginners (2026)

Learn how to build a REST API with Django and Django REST Framework from scratch. Complete step-by-step tutorial with code examples.

May 14, 202610 min read
Share
Advertisement (not configured)

What We Are Building

In this tutorial you will build a fully working REST API using Django and Django REST Framework (DRF). By the end you will have API endpoints that can:

  • List all items
  • Get a single item
  • Create a new item
  • Update an item
  • Delete an item

This is called a CRUD API — Create, Read, Update, Delete. It is the foundation of almost every web application.

What You Need

  • Python 3.10 or higher installed
  • Basic knowledge of Python
  • A terminal / command prompt

No Django experience needed — we start from zero.

Step 1 — Set Up Your Project

Create a folder and set up a virtual environment:

mkdir django-api
cd django-api

# Create virtual environment
python -m venv venv

# Activate it (Mac/Linux)
source venv/bin/activate

# Activate it (Windows)
venv\Scripts\activate

Install Django and Django REST Framework:

pip install django djangorestframework

Create a new Django project and app:

django-admin startproject myproject .
python manage.py startapp api

Your folder structure should look like this:

django-api/
├── myproject/
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── api/
│   ├── models.py
│   ├── views.py
│   └── urls.py
└── manage.py

Step 2 — Configure Settings

Open myproject/settings.py and add rest_framework and api to INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',  # Add this
    'api',             # Add this
]

Step 3 — Create the Model

We will build a simple Task API. Open api/models.py:

from django.db import models

class Task(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    completed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-created_at']

Run migrations to create the database table:

python manage.py makemigrations
python manage.py migrate

Step 4 — Create the Serializer

A serializer converts your model data to JSON (and back). Create a new file api/serializers.py:

from rest_framework import serializers
from .models import Task

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['id', 'title', 'description', 'completed', 'created_at']
        read_only_fields = ['id', 'created_at']

That is all you need. DRF handles the conversion automatically.

Step 5 — Create the Views

Open api/views.py and write your API views:

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Task
from .serializers import TaskSerializer


@api_view(['GET', 'POST'])
def task_list(request):
    """List all tasks or create a new task."""

    if request.method == 'GET':
        tasks = Task.objects.all()
        serializer = TaskSerializer(tasks, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = TaskSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PUT', 'DELETE'])
def task_detail(request, pk):
    """Get, update, or delete a single task."""

    try:
        task = Task.objects.get(pk=pk)
    except Task.DoesNotExist:
        return Response({'error': 'Task not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = TaskSerializer(task)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = TaskSerializer(task, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        task.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Step 6 — Set Up URLs

Create api/urls.py:

from django.urls import path
from . import views

urlpatterns = [
    path('tasks/', views.task_list, name='task-list'),
    path('tasks/<int:pk>/', views.task_detail, name='task-detail'),
]

Now connect it to the main project URLs. Open myproject/urls.py:

from django.contrib import admin
from django.urls import path, include

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

Step 7 — Test Your API

Start the development server:

python manage.py runserver

Your API is now live at http://127.0.0.1:8000/api/

Test with curl:

# Get all tasks
curl http://127.0.0.1:8000/api/tasks/

# Create a new task
curl -X POST http://127.0.0.1:8000/api/tasks/ \
  -H "Content-Type: application/json" \
  -d '{"title": "Learn Django", "description": "Build a REST API"}'

# Get a single task
curl http://127.0.0.1:8000/api/tasks/1/

# Update a task
curl -X PUT http://127.0.0.1:8000/api/tasks/1/ \
  -H "Content-Type: application/json" \
  -d '{"title": "Learn Django", "description": "Done!", "completed": true}'

# Delete a task
curl -X DELETE http://127.0.0.1:8000/api/tasks/1/

DRF also gives you a browsable API — open http://127.0.0.1:8000/api/tasks/ in your browser and you will see a nice UI to test your endpoints.

Step 8 — Use ViewSets (Cleaner Code)

The function-based views above are easy to understand but there is a cleaner way using ViewSets. Here is the same API in fewer lines:

# api/views.py
from rest_framework import viewsets
from .models import Task
from .serializers import TaskSerializer

class TaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer
# api/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import TaskViewSet

router = DefaultRouter()
router.register(r'tasks', TaskViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

This gives you all 5 endpoints automatically — list, create, retrieve, update, delete — with just 3 lines in the view.

What's Next

Now that you have a working REST API, here are the next steps to make it production ready:

  1. Add authentication — use rest_framework.authentication.TokenAuthentication so only logged-in users can access the API
  2. Add filtering — use django-filter to let clients filter tasks by completed=true
  3. Add pagination — add PAGE_SIZE = 10 to your DRF settings so large lists are paginated
  4. Deploy to Render — push to GitHub, connect to Render, and your API is live for free
# settings.py — add this for pagination and authentication
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
}

Django REST Framework is one of the most powerful tools in a Python developer's toolkit. Every web app needs an API and DRF makes it fast and clean to build one.

Advertisement (not configured)

Written by

Raretechsol

Software company from Pakistan, specializing in Python and JavaScript. Passionate about automation, AI, and building practical web applications.

Related Articles