Serializers & Views
Django REST Framework: Serializers & Views Django REST Framework (DRF) adds powerful tools for building REST APIs on top of Django. Core concepts: Serializers (…
Django REST Framework: Serializers & Views
Django REST Framework (DRF) adds powerful tools for building REST APIs on top of Django. Core concepts: Serializers (data validation + transformation), Views (request handling), and Routers (URL routing).
Setup
pip install djangorestframework
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}Serializers
from rest_framework import serializers
from .models import Article
# ModelSerializer — automatically maps model fields
class ArticleSerializer(serializers.ModelSerializer):
author_name = serializers.SerializerMethodField() # computed field
class Meta:
model = Article
fields = ['id', 'title', 'content', 'author', 'author_name', 'created_at']
read_only_fields = ['id', 'created_at', 'author']
def get_author_name(self, obj):
return obj.author.get_full_name()
def validate_title(self, value):
if len(value) < 5:
raise serializers.ValidationError("Title too short.")
return value
def validate(self, attrs):
# Cross-field validation
if attrs.get('published') and not attrs.get('content'):
raise serializers.ValidationError("Published articles must have content.")
return attrs
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
return super().create(validated_data)
# Nested serializer
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['id', 'text', 'created_at']
class ArticleDetailSerializer(ArticleSerializer):
comments = CommentSerializer(many=True, read_only=True)
class Meta(ArticleSerializer.Meta):
fields = ArticleSerializer.Meta.fields + ['comments']
# Usage
serializer = ArticleSerializer(article) # serialize single
serializer = ArticleSerializer(queryset, many=True) # serialize list
serializer = ArticleSerializer(data=request.data) # deserialize
if serializer.is_valid():
serializer.save()
else:
print(serializer.errors)Class-Based Views
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
serializer = ArticleSerializer(data=request.data, context={'request': request})
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)
class ArticleDetailView(APIView):
def get_object(self, pk):
try:
return Article.objects.get(pk=pk)
except Article.DoesNotExist:
raise Http404
def get(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
def put(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article, data=request.data, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def patch(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
article = self.get_object(pk)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py
urlpatterns = [
path('articles/', ArticleListView.as_view()),
path('articles/<int:pk>/', ArticleDetailView.as_view()),
]Generic Views
from rest_framework import generics
# Pre-built CRUD views — less boilerplate
class ArticleListCreateView(generics.ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_queryset(self):
# Dynamic filtering
return Article.objects.filter(author=self.request.user)
class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Other generics:
# ListAPIView, CreateAPIView
# RetrieveAPIView, UpdateAPIView, DestroyAPIView