Introduction
Django REST Framework (DRF) provides powerful tools for building RESTful APIs. This tutorial covers serializers, viewsets, routers, and authentication.
Serializers
# serializers.py
from rest_framework import serializers
from .models import Article, Author, Tag
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ['id', 'name', 'slug']
class AuthorSerializer(serializers.ModelSerializer):
books_count = serializers.SerializerMethodField()
class Meta:
model = Author
fields = ['id', 'name', 'email', 'bio', 'books_count']
def get_books_count(self, obj):
return obj.books.count()
class ArticleSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True)
author_id = serializers.IntegerField(write_only=True)
tags = TagSerializer(many=True, read_only=True)
tags_ids = serializers.ListField(
child=serializers.IntegerField(),
write_only=True
)
class Meta:
model = Article
fields = ['id', 'title', 'content', 'author', 'author_id',
'tags', 'tags_ids', 'published', 'created_at']
read_only_fields = ['created_at']
def validate_title(self, value):
if len(value) < 5:
raise serializers.ValidationError('Title too short')
return value
def create(self, validated_data):
tags_ids = validated_data.pop('tags_ids', [])
article = Article.objects.create(**validated_data)
article.tags.set(tags_ids)
return article
Viewsets and Views
# views.py
from rest_framework import viewsets, generics, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from .models import Article, Author
from .serializers import ArticleSerializer, AuthorSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated]
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['title', 'content']
ordering_fields = ['created_at', 'published']
def get_queryset(self):
return Article.objects.filter(author=self.request.user)
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
article = self.get_object()
article.published = True
article.save()
return Response({'status': 'published'})
@action(detail=False, methods=['get'])
def published(self, request):
articles = self.queryset.filter(published=True)
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
class AuthorListView(generics.ListCreateAPIView):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
Routers and URLs
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet, AuthorListView
router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')
urlpatterns = [
path('', include(router.urls)),
path('authors/', AuthorListView.as_view()),
]
Authentication
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
# permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user or request.user.is_staff
Practice Problems
- Create a serializer that handles nested relationships with custom validation
- Implement a ViewSet with custom actions for bulk operations
- Add pagination to a list view
- Configure token-based authentication
- Create a custom permission class for role-based access