Django REST Framework: Routers, Pagination & ViewSets
ViewSets & Routers
ViewSets combine the logic for a set of related views in a single class. Routers automatically generate URL patterns for ViewSets.
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated, IsAuthorOrReadOnly]
def get_queryset(self):
return Article.objects.filter(author=self.request.user)
def get_serializer_class(self):
if self.action == 'retrieve':
return ArticleDetailSerializer
return ArticleSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)
# Custom action
@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
def publish(self, request, pk=None):
article = self.get_object()
article.status = 'published'
article.save()
return Response({'status': 'published'})
@action(detail=False, methods=['get'])
def featured(self, request):
featured = Article.objects.filter(is_featured=True)
serializer = self.get_serializer(featured, many=True)
return Response(serializer.data)
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('articles', ArticleViewSet, basename='article')
# Generates:
# GET/POST /articles/
# GET/PUT/PATCH/DELETE /articles/<pk>/
# POST /articles/<pk>/publish/
# GET /articles/featured/
urlpatterns = [
path('api/', include(router.urls)),
]
# ReadOnlyModelViewSet — only list() and retrieve()
class PublicArticleViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Article.objects.filter(status='published')
serializer_class = ArticleSerializer
permission_classes = [AllowAny]Pagination
# settings.py (global)
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
# Custom pagination classes
from rest_framework.pagination import PageNumberPagination, CursorPagination
class LargeResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size' # ?page_size=50
max_page_size = 1000
class ArticleCursorPagination(CursorPagination):
page_size = 20
ordering = '-created_at' # must be unique, stable field
# Response format (PageNumberPagination):
# {
# "count": 1023,
# "next": "http://api.example.com/articles/?page=2",
# "previous": null,
# "results": [...]
# }
# Per-view pagination
class ArticleViewSet(viewsets.ModelViewSet):
pagination_class = LargeResultsSetPaginationThrottling & Versioning
# Throttling (rate limiting)
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day',
}
}
# Per-view throttle
class ArticleView(APIView):
throttle_classes = [UserRateThrottle]
# URL versioning
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1', 'v2'],
'VERSION_PARAM': 'version',
}
# urls.py
urlpatterns = [
path('api/<version>/articles/', ArticleListView.as_view()),
]
# In view
class ArticleListView(APIView):
def get(self, request, *args, **kwargs):
if request.version == 'v2':
serializer = ArticleV2Serializer(...)
else:
serializer = ArticleSerializer(...)Best Practices
Use ModelViewSet + Router for standard CRUD — eliminates repetitive URL and view code.
Return appropriate HTTP status codes: 201 Created, 204 No Content for delete, 400 for validation errors.
Use select_related/prefetch_related in get_queryset() to avoid N+1 queries.
Handle exceptions with custom exception handlers in settings: EXCEPTION_HANDLER.
Use DRF Spectacular or drf-yasg to auto-generate OpenAPI/Swagger docs from your views.
Test with APIClient: client = APIClient(); client.force_authenticate(user=user); client.get("/api/articles/")
Throttle unauthenticated endpoints to prevent abuse — default anon: 100/day is a good start.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free