Full-Stack

Building REST APIs with Django & DRF

Introduction

Django Rest Framework (DRF) is the gold standard for building REST APIs in Python. In the Orbital multi-tenant platform project, we used DRF to power all data exchange between the React frontend and the Django backend. This guide covers the key building blocks โ€” serializers, viewsets, authentication, and query optimization.

Step 1 โ€” Install & Configure DRF

pip install djangorestframework djangorestframework-simplejwt

# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 25,
}

Step 2 โ€” Define Your Serializer

Serializers translate between complex Django model instances and JSON. Use ModelSerializer to auto-generate fields from your model:

from rest_framework import serializers
from .models import Beneficiary

class BeneficiarySerializer(serializers.ModelSerializer):
    full_name = serializers.SerializerMethodField()

    class Meta:
        model = Beneficiary
        fields = ['id', 'full_name', 'district', 'enrollment_date', 'is_active']
        read_only_fields = ['id', 'enrollment_date']

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

๐Ÿ’ก Tip: Use select_related and prefetch_related in your queryset to prevent N+1 queries โ€” a common performance killer in DRF APIs with nested serializers.

Step 3 โ€” Create a ViewSet

ViewSets combine list, create, retrieve, update and delete into a single class. Register it with a router to auto-generate URLs:

from rest_framework import viewsets, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Beneficiary
from .serializers import BeneficiarySerializer

class BeneficiaryViewSet(viewsets.ModelViewSet):
    serializer_class = BeneficiarySerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['first_name', 'last_name', 'district']
    ordering_fields = ['enrollment_date', 'district']

    def get_queryset(self):
        return Beneficiary.objects.select_related('program') \
            .filter(tenant=self.request.tenant, is_active=True)

    @action(detail=False, methods=['get'])
    def summary(self, request):
        qs = self.get_queryset()
        return Response({'total': qs.count(), 'districts': qs.values('district').distinct().count()})

Step 4 โ€” Register URLs

from rest_framework.routers import DefaultRouter
from .views import BeneficiaryViewSet

router = DefaultRouter()
router.register(r'beneficiaries', BeneficiaryViewSet, basename='beneficiary')

urlpatterns = router.urls
# Auto-generates: GET/POST /beneficiaries/, GET/PUT/DELETE /beneficiaries/{id}/

Step 5 โ€” Secure with JWT

# urls.py (project level)
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns += [
    path('api/token/', TokenObtainPairView.as_view()),
    path('api/token/refresh/', TokenRefreshView.as_view()),
]

Conclusion

DRF's combination of serializers, viewsets, and routers lets you build a fully featured, secure REST API with minimal boilerplate. Pair it with JWT authentication and careful queryset optimization, and you have an API ready for production enterprise workloads.

← Back to Articles Next: Kubernetes Deployment →