Django REST Framework Routers
Automatic URL routing for ViewSets
🔗 What are Routers?
Routers automatically generate URL patterns for your ViewSets. Instead of manually defining URLs for each action, routers create them automatically, ensuring consistent and RESTful URL structures across your API.
# Automatic URL generation
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'books', BookViewSet)
urlpatterns = router.urls
Generated URLs:
/books/ - List/Create
/books/{id}/ - Retrieve/Update/Delete
Router Types
SimpleRouter
Basic URL routing
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register(r'books', BookViewSet)
DefaultRouter
Includes API root view
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'books', BookViewSet)
Custom Routes
Add custom URL patterns
router.register(r'books', BookViewSet)
urlpatterns = [
path('custom/', custom_view),
] + router.urls
Multiple Routers
Organize API versions
router_v1 = DefaultRouter()
router_v2 = DefaultRouter()
router_v1.register(r'books', BookViewSetV1)
🔹 DefaultRouter
The most commonly used router that creates a browsable API root view and standard RESTful URL patterns for your ViewSets:
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet, AuthorViewSet
# Create router instance
router = DefaultRouter()
# Register ViewSets
router.register(r'books', BookViewSet, basename='book')
router.register(r'authors', AuthorViewSet, basename='author')
# Include router URLs
urlpatterns = [
path('api/', include(router.urls)),
]
Generated URL Patterns:
GET /api/ - API root view
GET /api/books/ - List books
POST /api/books/ - Create book
GET /api/books/{id}/ - Retrieve book
PUT /api/books/{id}/ - Update book
PATCH /api/books/{id}/ - Partial update
DELETE /api/books/{id}/ - Delete book
GET /api/authors/ - List authors
POST /api/authors/ - Create author
GET /api/authors/{id}/ - Retrieve author
🔹 SimpleRouter
A lightweight router without the API root view. Use when you don't need the browsable API homepage:
# urls.py
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import BookViewSet
router = SimpleRouter()
router.register(r'books', BookViewSet, basename='book')
urlpatterns = [
path('api/', include(router.urls)),
]
Differences from DefaultRouter:
- No API root view at /api/
- Slightly smaller URL configuration
- Same ViewSet URL patterns
- Better for production APIs without browsable interface
🔹 Registering ViewSets
Register multiple ViewSets to create a complete API structure with organized endpoints:
# urls.py
from rest_framework.routers import DefaultRouter
from .views import (
BookViewSet,
AuthorViewSet,
CategoryViewSet,
ReviewViewSet
)
router = DefaultRouter()
# Register all ViewSets
router.register(r'books', BookViewSet, basename='book')
router.register(r'authors', AuthorViewSet, basename='author')
router.register(r'categories', CategoryViewSet, basename='category')
router.register(r'reviews', ReviewViewSet, basename='review')
# Use in urlpatterns
urlpatterns = [
path('api/v1/', include(router.urls)),
]
Complete API Structure:
/api/v1/ - API root /api/v1/books/ - Books endpoint /api/v1/authors/ - Authors endpoint /api/v1/categories/ - Categories endpoint /api/v1/reviews/ - Reviews endpoint
🔹 Custom Actions with Routers
Routers automatically generate URLs for custom actions defined with the @action decorator:
# views.py
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
@action(detail=False, methods=['get'])
def recent(self, request):
recent_books = Book.objects.order_by('-created_at')[:10]
serializer = self.get_serializer(recent_books, many=True)
return Response(serializer.data)
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
book = self.get_object()
book.is_published = True
book.save()
return Response({'status': 'published'})
# urls.py
router = DefaultRouter()
router.register(r'books', BookViewSet, basename='book')
urlpatterns = router.urls
Generated Custom URLs:
GET /books/recent/ - Recent books (list action)
POST /books/{id}/publish/ - Publish book (detail action)
🔹 Combining Routers with Custom URLs
Mix router-generated URLs with custom URL patterns for maximum flexibility:
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
# Router for ViewSets
router = DefaultRouter()
router.register(r'books', views.BookViewSet, basename='book')
router.register(r'authors', views.AuthorViewSet, basename='author')
# Custom URL patterns
urlpatterns = [
# Custom function-based views
path('api/search/', views.search_books, name='search'),
path('api/stats/', views.get_statistics, name='stats'),
# Custom class-based views
path('api/featured/', views.FeaturedBooksView.as_view(), name='featured'),
# Include router URLs
path('api/', include(router.urls)),
]
Final URL Structure:
/api/search/ - Custom search endpoint /api/stats/ - Custom statistics endpoint /api/featured/ - Custom featured books /api/books/ - Router-generated book endpoints /api/authors/ - Router-generated author endpoints
🔹 Nested Routers
Create nested URL structures for related resources using custom registration:
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'authors', views.AuthorViewSet, basename='author')
router.register(r'books', views.BookViewSet, basename='book')
# Nested routes for author's books
urlpatterns = [
path('api/', include(router.urls)),
path('api/authors//books/',
views.AuthorBooksView.as_view(),
name='author-books'),
]
# views.py
class AuthorBooksView(generics.ListAPIView):
serializer_class = BookSerializer
def get_queryset(self):
author_id = self.kwargs['author_id']
return Book.objects.filter(author_id=author_id)
Nested URL Example:
GET /api/authors/1/books/ - All books by author with ID 1
🔹 API Versioning with Routers
Organize different API versions using separate routers for backward compatibility:
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
# Version 1 Router
router_v1 = DefaultRouter()
router_v1.register(r'books', views.BookViewSetV1, basename='book')
# Version 2 Router
router_v2 = DefaultRouter()
router_v2.register(r'books', views.BookViewSetV2, basename='book')
router_v2.register(r'authors', views.AuthorViewSet, basename='author')
urlpatterns = [
path('api/v1/', include(router_v1.urls)),
path('api/v2/', include(router_v2.urls)),
]
Versioned API Structure:
/api/v1/books/ - Version 1 books endpoint /api/v2/books/ - Version 2 books endpoint /api/v2/authors/ - Version 2 authors endpoint (new)