Difficulty: Advanced
DRF provides multiple authentication schemes, each suited for different use cases. SessionAuthentication uses Django's session framework and is ideal for browser-based clients. TokenAuthentication uses a token header and is suited for mobile and single-page applications. JWT (JSON Web Tokens) through third-party packages like djangorestframework-simplejwt is the most popular choice for modern SPAs and mobile apps.
TokenAuthentication works by generating a unique token for each user. The client includes this token in the Authorization header of every request: 'Authorization: Token abc123...'. DRF validates the token and identifies the user. Tokens can be created through a built-in view (obtain_auth_token) or programmatically.
Permissions control who can access API endpoints. DRF provides several built-in permission classes: AllowAny (no restrictions), IsAuthenticated (logged-in users only), IsAdminUser (staff users only), IsAuthenticatedOrReadOnly (anyone can read, only authenticated can write). Custom permissions extend BasePermission and implement has_permission() or has_object_permission().
Pagination controls how large result sets are divided into pages. PageNumberPagination uses ?page=2 style. LimitOffsetPagination uses ?limit=10&offset=20 style. CursorPagination uses opaque cursors for consistent ordering with real-time data. Configure pagination globally in REST_FRAMEWORK settings or per-view with pagination_class.
Filtering narrows down results based on query parameters. DRF supports filtering through django-filter (DjangoFilterBackend), search (SearchFilter), and ordering (OrderingFilter). These backends are added to filter_backends on ViewSets and generate query parameters like ?category=electronics&search=laptop&ordering=-price.
Throttling limits the rate of API requests to prevent abuse. DRF provides AnonRateThrottle (for unauthenticated users) and UserRateThrottle (for authenticated users). Rates are specified as 'number/period' like '100/hour' or '1000/day'. Custom throttles can implement more complex rate limiting logic.
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
'rest_framework.authtoken', # Token auth app
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
# urls.py
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('api/token/', obtain_auth_token, name='api-token'),
]
# After running migrate, obtain a token:
# POST /api/token/ {"username": "john", "password": "pass123"}
# Response: {"token": "abc123def456..."}
# Use the token in requests:
# GET /api/articles/
# Authorization: Token abc123def456...
Add rest_framework.authtoken to INSTALLED_APPS and run migrate to create the token table. Clients POST credentials to obtain a token, then include it in the Authorization header for authenticated requests.
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""Allow owners to edit, everyone else can only read."""
def has_object_permission(self, request, view, obj):
# Read permissions for any request (GET, HEAD, OPTIONS)
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions only for the owner
return obj.author == request.user
class IsAdminOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user and request.user.is_staff
# Usage in ViewSet
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [permissions.IsAuthenticated, IsOwnerOrReadOnly]
has_permission() runs for all requests. has_object_permission() runs for single-object views. SAFE_METHODS includes GET, HEAD, OPTIONS. Multiple permission classes are ANDed together.
# settings.py - Global pagination
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
# Custom pagination class
from rest_framework.pagination import PageNumberPagination
class LargeResultPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
max_page_size = 100
# Per-view pagination
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = LargeResultPagination
# Response format:
# {
# "count": 150,
# "next": "http://api.example.com/articles/?page=2",
# "previous": null,
# "results": [{...}, {...}, ...]
# }
PageNumberPagination splits results into pages. page_size_query_param lets clients request custom page sizes. The response includes count, next, previous, and results. Set pagination_class per-view to override global settings.
# pip install django-filter
# settings.py
INSTALLED_APPS = ['django_filters']
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
}
# ViewSet with filtering
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'status', 'author']
search_fields = ['title', 'content', 'author__username']
ordering_fields = ['created_at', 'title', 'views']
ordering = ['-created_at'] # Default ordering
# Example API calls:
# GET /api/articles/?category=1&status=published
# GET /api/articles/?search=django+tutorial
# GET /api/articles/?ordering=-views
# GET /api/articles/?category=1&search=django&ordering=-created_at
DjangoFilterBackend filters by exact field values. SearchFilter searches across text fields. OrderingFilter sorts results. All three can be combined in a single request. filterset_fields, search_fields, and ordering_fields control which fields are available.
TokenAuth, JWT, Permissions, Pagination, Filtering, Throttling