Django REST Framework (DRF) has become the standard for building APIs in Python. Its powerful serialization, authentication, and browsable API make development efficient. At ZIRA Software, DRF powers our Python-based backend services.
Installation and Setup
pip install djangorestframework
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20
}
Serializers
# serializers.py
from rest_framework import serializers
from .models import Post, Comment, Author
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ['id', 'name', 'email']
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['id', 'content', 'created_at', 'author']
class PostSerializer(serializers.ModelSerializer):
author = AuthorSerializer(read_only=True)
comments = CommentSerializer(many=True, read_only=True)
comment_count = serializers.SerializerMethodField()
class Meta:
model = Post
fields = ['id', 'title', 'content', 'author', 'comments',
'comment_count', 'created_at', 'updated_at']
def get_comment_count(self, obj):
return obj.comments.count()
class PostCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['title', 'content']
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
return super().create(validated_data)
ViewSets and Routers
# views.py
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Post
from .serializers import PostSerializer, PostCreateSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.select_related('author').prefetch_related('comments')
def get_serializer_class(self):
if self.action in ['create', 'update', 'partial_update']:
return PostCreateSerializer
return PostSerializer
def get_queryset(self):
queryset = super().get_queryset()
# Filter by author
author_id = self.request.query_params.get('author')
if author_id:
queryset = queryset.filter(author_id=author_id)
return queryset
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
post = self.get_object()
post.published = True
post.save()
return Response({'status': 'published'})
@action(detail=False)
def recent(self, request):
recent = self.get_queryset().order_by('-created_at')[:5]
serializer = self.get_serializer(recent, many=True)
return Response(serializer.data)
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'posts', PostViewSet)
urlpatterns = router.urls
Authentication
# Token Authentication
from rest_framework.authtoken.models import Token
# Create token for user
token = Token.objects.create(user=user)
# Request with token
# Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
# Custom Authentication
from rest_framework.authentication import BaseAuthentication
class APIKeyAuthentication(BaseAuthentication):
def authenticate(self, request):
api_key = request.META.get('HTTP_X_API_KEY')
if not api_key:
return None
try:
api_client = APIClient.objects.get(key=api_key, active=True)
return (api_client.user, None)
except APIClient.DoesNotExist:
raise AuthenticationFailed('Invalid API key')
Permissions
from rest_framework.permissions import BasePermission
class IsAuthorOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
# Read permissions for any request
if request.method in ['GET', 'HEAD', 'OPTIONS']:
return True
# Write permissions only for author
return obj.author == request.user
class PostViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
Filtering and Search
# Install django-filter
pip install django-filter
# settings.py
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
]
}
# views.py
class PostViewSet(viewsets.ModelViewSet):
filterset_fields = ['author', 'published', 'category']
search_fields = ['title', 'content']
ordering_fields = ['created_at', 'title']
ordering = ['-created_at']
Conclusion
Django REST Framework provides everything needed for professional API development. Its serializers, viewsets, and authentication make building robust APIs straightforward.
Building Python APIs? Contact ZIRA Software for Django REST Framework development.