Looking to turn your Django web applications into powerful, scalable APIs? The Django REST Framework (DRF) makes it effortless to build robust RESTful services with minimal boiler‑plate. In this step‑by‑step tutorial we’ll walk through everything you need to know—from setting up a clean development environment to deploying a production‑ready API—so you can start delivering data to mobile apps, single‑page front‑ends, or third‑party services in no time.
What is Django REST Framework?
Django REST Framework (often abbreviated as DRF) is a flexible, open‑source toolkit that extends Django’s core capabilities to support the creation of Web APIs. It provides:
- Powerful
Serializerclasses for converting complex data types to JSON. - Class‑based
ViewSetand generic views that reduce repetitive code. - Automatic URL routing via
DefaultRouter. - Built‑in authentication, permissions, throttling, pagination, and content negotiation.
- Comprehensive browsable API for rapid debugging.
Because DRF sits on top of Django, you retain all of Django’s strengths—ORM, admin, middleware—while gaining a modern API layer.
Setting Up the Development Environment
Prerequisites
Before diving in, make sure you have the following installed on your machine:
- Python 3.9+ (the latest stable release is recommended).
- pip, the Python package manager.
- virtualenv or
python -m venvfor isolated environments. - Git (optional but useful for version control).
Creating a Virtual Environment
python -m venv drf-tutorial-env
source drf-tutorial-env/bin/activate # On Windows use `drf-tutorial-env\Scripts\activate`
pip install --upgrade pip
Installing Django and DRF
pip install django djangorestframework
Verify the installation:
python -m django --version
# Should output something like 5.0.2
Creating a New Django Project
Run the standard Django start‑project command and create an app called api where our API logic will live.
django-admin startproject mysite
cd mysite
python manage.py startapp api
Next, register the app and DRF in mysite/settings.py:
INSTALLED_APPS = [
# Default Django apps...
'rest_framework',
'api',
]
Building Your First API
Defining a Simple Model
Let’s create a Book model that stores basic bibliographic data.
# api/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
published = models.DateField()
isbn = models.CharField(max_length=13, unique=True)
def __str__(self):
return f"{self.title} by {self.author}"
Run migrations to create the table:
python manage.py makemigrations api
python manage.py migrate
Serializers: Bridging Models and JSON
A serializer translates model instances into JSON and validates incoming data.
# api/serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title', 'author', 'published', 'isbn']
ViewSets: CRUD Operations in One Class
DRF’s ModelViewSet gives you a full set of create, retrieve, update, and delete (CRUD) actions with just a few lines.
# api/views.py
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
Routing with DefaultRouter
The router automatically generates URL patterns for the viewset.
# api/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Don’t forget to include the app’s URLs in the project’s root urls.py:
# mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')), # <‑‑ API endpoint
]
Testing the API Locally
Start the development server and explore the browsable API at http://127.0.0.1:8000/api/books/:
python manage.py runserver
The interface lets you list books, add new entries, and edit or delete existing ones—all without leaving your browser.
Adding Authentication and Permissions
For production APIs you’ll want to restrict access. DRF ships with several authentication schemes; we’ll enable token authentication.
Install the token package
pip install djangorestframework-simplejwt
Configure settings
# mysite/settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
Create token endpoints
# mysite/urls.py (add the following)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns += [
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
Now, only users with a valid JWT can access /api/books/. You can further fine‑tune permissions per viewset by overriding permission_classes.
Pagination, Filtering, and Ordering
Large collections need efficient navigation. DRF makes pagination a one‑line configuration.
Enable pagination
# mysite/settings.py
REST_FRAMEWORK.update({
'PAGE_SIZE': 10,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
})
Filtering and ordering
# api/views.py (add imports)
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter]
filterset_fields = ['author', 'published']
ordering_fields = ['title', 'published']
search_fields = ['title', 'author']
Install the filter backend:
pip install django-filter
Now you can query /api/books/?author=Jane%20Austen&ordering=-published to get sorted results.
Automated Testing with Django’s Test Client
Writing tests guarantees that future changes won’t break your API.
# api/tests.py
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Book
from django.contrib.auth.models import User
from rest_framework_simplejwt.tokens import RefreshToken
class BookAPITest(APITestCase):
def setUp(self):
self.user = User.objects.create_user(username='tester', password='secret')
refresh = RefreshToken.for_user(self.user)
self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {refresh.access_token}')
self.book = Book.objects.create(
title='Pride and Prejudice',
author='Jane Austen',
published='1813-01-28',
isbn='1112223334445'
)
def test_list_books(self):
url = reverse('book-list') # auto‑generated by router
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 1)
def test_create_book(self):
url = reverse('book-list')
data = {
'title': 'Emma',
'author': 'Jane Austen',
'published': '1815-12-23',
'isbn':
Leave a Reply