Django REST Introduction
What is Django REST Framework?
Django REST Framework (DRF) is a powerful and flexible toolkit built on top of Django that makes it easy to build Web APIs. If you're familiar with Django's traditional approach to building web applications, DRF extends this functionality to easily create RESTful APIs that can serve your application's data to various clients including mobile applications, JavaScript frameworks, or other services.
REST (Representational State Transfer) is an architectural style for designing networked applications. RESTful APIs use HTTP requests to perform CRUD (Create, Read, Update, Delete) operations on resources, typically represented in formats like JSON or XML.
Why Use Django REST Framework?
- Web Browsable API: DRF provides a browsable web API, making development and testing much easier
- Authentication Policies: Includes OAuth1, OAuth2, Basic Authentication, and more
- Serialization: Powerful serialization that supports both ORM and non-ORM data sources
- Extensive Documentation: Well-documented with many tutorials and examples
- Community & Ecosystem: Large community and extensive ecosystem of packages
Setting Up Django REST Framework
Let's start by setting up a new Django project with REST Framework:
Installation
# Create a virtual environment
python -m venv env
source env/bin/activate # On Windows: env\Scripts\activate
# Install Django and Django REST Framework
pip install django djangorestframework
Project Setup
# Create a new Django project
django-admin startproject tutorial
cd tutorial
# Create an app
python manage.py startapp api
Configure Django REST Framework
Update your settings.py
to include REST Framework:
# tutorial/settings.py
INSTALLED_APPS = [
# Django apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third-party apps
'rest_framework', # Add this line
# Your apps
'api',
]
# Add REST Framework settings
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
Creating Your First API
Let's create a simple API for a book library system. We'll follow these steps:
- Define models
- Create serializers
- Set up views
- Configure URLs
1. Define Models
First, let's create a simple Book model:
# api/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
publication_date = models.DateField()
isbn = models.CharField(max_length=13, unique=True)
def __str__(self):
return self.title
Run migrations to create the database table:
python manage.py makemigrations
python manage.py migrate
2. Create Serializers
Serializers in DRF convert complex data like querysets and model instances to Python datatypes that can then be easily rendered into JSON, XML, or other content types.
# api/serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date', 'isbn']
This BookSerializer
automatically creates fields corresponding to the Book
model and provides validation, create, and update operations.
3. Set Up Views
DRF offers several types of views. Here, we'll use ViewSets
which provide CRUD operations with minimal code:
# api/views.py
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows books to be viewed or edited.
"""
queryset = Book.objects.all().order_by('-publication_date')
serializer_class = BookSerializer
The ModelViewSet
class automatically provides .list()
, .retrieve()
, .create()
, .update()
, and .destroy()
actions.
4. Configure URLs
Now set up the URLs to access your API:
# tutorial/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from api.views import BookViewSet
# Create a router and register our viewsets
router = routers.DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
Testing Your API
Run your server with:
python manage.py runserver
Now you can access your API at:
Try accessing this URL in your browser. You should see DRF's browsable API interface:
The browsable API allows you to:
- View all books (GET)
- Create new books (POST)
- View individual books (GET with ID)
- Update books (PUT/PATCH)
- Delete books (DELETE)
Making API Requests
Using the Browsable API
With the browsable API, you can interact directly through your browser:
- List all books: Visit http://127.0.0.1:8000/api/books/
- Create a new book: Fill out the form at the bottom of the page
- View a book: Click on a book's URL (e.g., http://127.0.0.1:8000/api/books/1/)
- Update/Delete: Use the forms provided on the detail page
Using cURL
You can also use cURL to interact with your API:
GET all books:
curl -X GET http://127.0.0.1:8000/api/books/
POST a new book:
curl -X POST http://127.0.0.1:8000/api/books/ \
-H "Content-Type: application/json" \
-d '{"title": "Django for Beginners", "author": "William S. Vincent", "publication_date": "2020-01-01", "isbn": "9781234567890"}'
GET a specific book:
curl -X GET http://127.0.0.1:8000/api/books/1/
PUT (update) a book:
curl -X PUT http://127.0.0.1:8000/api/books/1/ \
-H "Content-Type: application/json" \
-d '{"title": "Django for Professionals", "author": "William S. Vincent", "publication_date": "2020-04-01", "isbn": "9781234567890"}'
DELETE a book:
curl -X DELETE http://127.0.0.1:8000/api/books/1/
Real-world Application: Building a To-Do API
Let's expand our knowledge by creating a simple To-Do API:
Model
# 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
Serializer
# 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']
Views
DRF offers different ways to create API views. Let's see three different approaches:
1. Using Function-Based Views
# api/views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
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)
2. Using Class-Based Views
# api/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Task
from .serializers import TaskSerializer
class TaskListView(APIView):
"""
List all tasks, or create a new task.
"""
def get(self, request, format=None):
tasks = Task.objects.all()
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)
def post(self, request, format=None):
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)
3. Using ViewSets (most concise)
# api/views.py
from rest_framework import viewsets
from .models import Task
from .serializers import TaskSerializer
class TaskViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
"""
queryset = Task.objects.all()
serializer_class = TaskSerializer
URLs Configuration
With ViewSets, URL configuration is very simple:
# tutorial/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from api.views import TaskViewSet
router = DefaultRouter()
router.register(r'tasks', TaskViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Authentication and Permissions
When building APIs, you often need to restrict access. DRF provides various authentication and permission classes.
Adding Basic Authentication
Update your settings.py
:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
Using Token Authentication
- Add
'rest_framework.authtoken'
to yourINSTALLED_APPS
insettings.py
- Run
python manage.py migrate
to create the token table - Update your authentication classes:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
- Create a token for a user:
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
user = User.objects.get(username='your_username')
token = Token.objects.create(user=user)
print(token.key)
- To use the token in requests, add the header:
Authorization: Token your_token_key
Pagination
As your API grows, you'll want to paginate your results:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
Summary
In this introduction to Django REST Framework, we've covered:
- Setting up Django REST Framework in a project
- Creating models and serializers
- Building views using different approaches (function-based, class-based, ViewSets)
- Configuring URLs and routers
- Testing APIs using the browsable API and cURL
- Adding authentication and permissions
- Implementing pagination
Django REST Framework simplifies building powerful and flexible APIs. With minimal code, you can create a complete RESTful API with browsable endpoints, authentication, and serialization.
Additional Resources
- Django REST Framework Official Documentation
- Django REST Framework Tutorial
- Django for APIs - Book by William S. Vincent
Exercises
- Extend the Book API to include a "Category" model with a one-to-many relationship (a book belongs to a category)
- Implement token authentication for your API
- Add search functionality to filter books by title or author
- Create a custom permission class that only allows book creators to modify their books
- Build a nested serializer to display related data (like showing category details when requesting a book)
By completing these exercises, you'll gain practical experience with many of Django REST Framework's powerful features!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)