Django REST Framework: Advanced API Development Patterns
4 mins read

Django REST Framework: Advanced API Development Patterns

Django REST Framework provides a comprehensive toolkit for building robust, scalable APIs. This guide explores advanced patterns for professional API development using DRF’s powerful features.

Django REST Framework logo - Basics of Django Rest Framework | Caktus Group
Django REST Framework logo – Basics of Django Rest Framework | Caktus Group

Advanced Serializer Patterns

REST API architecture diagram - Rest API Architecture. REST API architecture refers to the… | by ...
REST API architecture diagram – Rest API Architecture. REST API architecture refers to the… | by …

DRF serializers handle complex data validation and transformation requirements:


from rest_framework import serializers
from django.contrib.auth.models import User
from django.db import transaction
import re

class DynamicFieldsSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        fields = kwargs.pop('fields', None)
        super().__init__(*args, **kwargs)

        if fields is not None:
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

class UserDetailSerializer(DynamicFieldsSerializer):
    full_name = serializers.SerializerMethodField()
    profile_completion = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'first_name', 'last_name',
                 'full_name', 'profile_completion', 'date_joined']
        read_only_fields = ['id', 'date_joined']

    def get_full_name(self, obj):
        return f"{obj.first_name} {obj.last_name}".strip()

    def get_profile_completion(self, obj):
        fields = ['first_name', 'last_name', 'email']
        completed = sum(1 for field in fields if getattr(obj, field))
        return round((completed / len(fields)) * 100, 2)

class UserCreateSerializer(serializers.ModelSerializer):
    password_confirm = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'password_confirm',
                 'first_name', 'last_name']
        extra_kwargs = {'password': {'write_only': True}}

    def validate(self, attrs):
        if attrs['password'] != attrs.pop('password_confirm'):
            raise serializers.ValidationError("Passwords don't match")
        return attrs

    def validate_password(self, value):
        if len(value) < 8:
            raise serializers.ValidationError("Password too short")
        if not re.search(r'[A-Z]', value):
            raise serializers.ValidationError("Must contain uppercase")
        return value

    @transaction.atomic
    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

Advanced ViewSet Implementation

REST API architecture diagram - REST vs. GraphQL: Which API Design Style Is Right for Your ...
REST API architecture diagram - REST vs. GraphQL: Which API Design Style Is Right for Your ...

ViewSets provide powerful API organization with custom actions and filtering:


from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django_filters import rest_framework as filters
from django.db.models import Q

class UserFilter(filters.FilterSet):
    search = filters.CharFilter(method='filter_search')
    created_after = filters.DateTimeFilter(field_name='date_joined', lookup_expr='gte')

    class Meta:
        model = User
        fields = ['is_active', 'is_staff']

    def filter_search(self, queryset, name, value):
        return queryset.filter(
            Q(username__icontains=value) |
            Q(email__icontains=value) |
            Q(first_name__icontains=value) |
            Q(last_name__icontains=value)
        )

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    filterset_class = UserFilter
    permission_classes = [IsAuthenticated]

    def get_serializer_class(self):
        if self.action == 'create':
            return UserCreateSerializer
        return UserDetailSerializer

    def get_queryset(self):
        queryset = User.objects.all()

        # Optimize queries based on action
        if self.action == 'list':
            queryset = queryset.select_related()

        # Permission-based filtering
        if not self.request.user.is_staff:
            queryset = queryset.filter(is_active=True)

        return queryset

    @action(detail=True, methods=['post'])
    def set_password(self, request, pk=None):
        user = self.get_object()

        if request.user != user and not request.user.is_staff:
            return Response({'error': 'Permission denied'},
                          status=status.HTTP_403_FORBIDDEN)

        serializer = PasswordChangeSerializer(data=request.data)
        if serializer.is_valid():
            user.set_password(serializer.validated_data['password'])
            user.save()
            return Response({'message': 'Password updated'})

        return Response(serializer.errors,
                       status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['get'])
    def statistics(self, request):
        return Response({
            'total_users': User.objects.count(),
            'active_users': User.objects.filter(is_active=True).count(),
            'staff_users': User.objects.filter(is_staff=True).count()
        })

Django REST Framework's comprehensive features enable developers to build enterprise-grade APIs that handle complex business requirements while maintaining clean, maintainable code.

Leave a Reply

Your email address will not be published. Required fields are marked *