Welcome to the ultimate Python Django REST Framework (DRF) tutorial! Whether you’re a seasoned Django developer looking to expose your models as a robust API, or a newcomer eager to dive into the world of web services, this guide will walk you through every essential step—from setting up your environment to deploying a production‑ready API. By the end of this tutorial, you’ll have a fully functional RESTful service built with Django, DRF, and Python, ready to power mobile apps, single‑page applications, or any client that speaks HTTP.
What Is Django REST Framework?
Django REST Framework, commonly abbreviated as DRF, is a powerful, flexible toolkit for building Web APIs on top of the Django web framework. It extends Django’s core capabilities with:
- Serializers that translate complex data types (like Django models) into JSON, XML, or other content types.
- Class‑based views and viewsets that simplify CRUD operations.
- Built‑in authentication, permission, and throttling mechanisms.
- Automatic API documentation via tools like Swagger or ReDoc.
Because DRF follows the same principles as Django—reusability, pluggability, and “batteries‑included”—you’ll feel right at home while building APIs that are clean, testable, and scalable.
Prerequisites and Environment Setup
System Requirements
- Python 3.9 or newer (Python 3.12 recommended)
- Virtualenv or any other virtual environment tool
- Git (optional but useful for version control)
Step‑by‑Step Installation
- Open a terminal and create a new virtual environment:
python -m venv drf-env source drf-env/bin/activate # On Windows use drf-env\Scripts\activate - Upgrade
pipand install Django and DRF:pip install --upgrade pip pip install django djangorestframework - Verify the installation:
python -c "import django, rest_framework; print('Django', django.get_version(), 'DRF', rest_framework.__version__)"
Creating Your First Django Project
Now that the environment is ready, let’s spin up a new Django project called blog_api and an app named posts that will host our API endpoints.
django-admin startproject blog_api
cd blog_api
python manage.py startapp posts
Don’t forget to register the new app and DRF in blog_api/settings.py:
INSTALLED_APPS = [
# Default Django apps…
'rest_framework',
'posts',
]
Designing the Data Model
For this tutorial we’ll use a simple Post model that represents a blog article.
# posts/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Run migrations to create the database tables:
python manage.py makemigrations
python manage.py migrate
Serializers: Converting Models to JSON
Serializers are the heart of any DRF API. They define how model instances are turned into JSON (or other formats) and back again.
# posts/serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'content', 'created_at']
ViewSets and Routers: Rapid CRUD Endpoints
DRF’s ModelViewSet gives you a full set of create, retrieve, update, and delete actions with just a few lines of code.
# posts/views.py
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all().order_by('-created_at')
serializer_class = PostSerializer
Next, wire the viewset to URLs using a router.
# posts/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import PostViewSet
router = DefaultRouter()
router.register(r'posts', PostViewSet, basename='post')
urlpatterns = [
path('', include(router.urls)),
]
Finally, include the app’s URLs in the project’s main urls.py file:
# blog_api/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('posts.urls')), # All API endpoints under /api/
]
Testing the API with the Browsable Interface
One of DRF’s biggest conveniences is the built‑in browsable API. Start the development server and explore:
python manage.py runserver
Navigate to http://127.0.0.1:8000/api/posts/. You’ll see a clean HTML interface that lets you list, create, update, and delete Post objects without writing any JavaScript.
Authentication, Permissions, and Security
For production APIs you’ll rarely expose data to the public. DRF supports multiple authentication schemes out of the box. Below is a quick setup for token‑based authentication.
Enable Token Authentication
# Install the token auth package
pip install djangorestframework-simplejwt
Add the authentication classes to settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
Create JWT Endpoints
# blog_api/urls.py (add imports)
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 authenticated users can access /api/posts/. Use tools like Postman or curl to obtain a token and include it in the Authorization: Bearer <token> header for subsequent requests.
Adding Custom Permissions
Suppose you want authors to edit only their own posts. Define a custom permission class:
# posts/permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object‑level permission to only allow owners of an object to edit it.
Assumes the model instance has an `author` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed for any request
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions only for the author
return obj.author == request.user
Apply it in the viewset:
# posts/views.py (add import)
from .permissions import IsOwnerOrReadOnly
class PostViewSet(viewsets.ModelViewSet):
...
permission_classes = [IsOwnerOrReadOnly]
Testing Your API with Automated Tests
DRF integrates seamlessly with Django’s test framework. Below is a minimal test suite that verifies CRUD operations.
# posts/tests.py
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Post
from django.contrib.auth.models import User
class PostAPITests(APITestCase):
def setUp(self):
self.user = User.objects.create_user(username='tester', password='secret')
self.client.login(username='tester', password='secret')
self.post = Post.objects.create(title='First Post', content='Hello World!')
def test_list_posts(self):
url = reverse('post-list')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_create_post(self):
url = reverse('post-list')
data = {'title': 'New Post', 'content': 'Testing create'}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Post.objects.count(), 2)
Best Practices and Common Pitfalls
- Version your API. Prefix URLs with
/api/v1/so you can evolve the contract without breaking existing clients. - Use pagination. Large result sets can overwhelm clients; DRF’s
PageNumberPaginationorLimitOffsetPaginationare easy to enable.
Leave a Reply