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.