Routers
When using ViewSets, you don't need to manually design your URLs. DRF routers automatically wire up your view logic to a standard set of RESTful endpoints, keeping your routing incredibly DRY and consistent.
The SimpleRouter
The SimpleRouter includes the standard set of routes for list, create, retrieve, update, partial_update, and destroy.
from rest_framework.routers import SimpleRouter
from . import views
router = SimpleRouter()
router.register(r'users', views.UserViewSet, basename='user')Registering router.register(r'users', UserViewSet) automatically generates:
| URL | HTTP Method | Action |
|---|---|---|
/users/ | GET | list() |
/users/ | POST | create() |
/users/{pk}/ | GET | retrieve() |
/users/{pk}/ | PUT | update() |
/users/{pk}/ | PATCH | partial_update() |
/users/{pk}/ | DELETE | destroy() |
The DefaultRouter
The DefaultRouter is identical to SimpleRouter, but it provides two additional benefits:
- It includes an automatic API root view that returns a dictionary mapping of all registered list views.
- It generates format suffix patterns (e.g.,
.jsonor.html) for all its routes natively, meaning you don't need to manually useformat_suffix_patternsin yoururls.py.
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', views.UserViewSet, basename='user')Adding to urlpatterns
There are two primary ways to add your router's generated URLs to your Django urlpatterns.
Using path() and include()
You can append the router's .urls property to your URL list using Django's standard path() and include() functions. This is incredibly useful if you want to namespace your API endpoints:
from django.urls import path, include
urlpatterns = [
# Prefixes all router-generated URLs with '/api/v1/'
path('api/v1/', include(router.urls)),
]Extending the list natively
Since .urls is just a standard list of Django URL patterns, you can simply append it to your existing list without needing include():
urlpatterns = [
path('custom/', custom_view),
]
urlpatterns += router.urlsExtra Actions
If you have defined custom endpoints on your ViewSet using the @action decorator, routers will automatically generate URLs for them as well.
# In your ViewSet
from rest_framework.decorators import action
class UserViewSet(ModelViewSet):
# ...
@action(detail=True, methods=['post'])
def set_password(self, request, pk=None):
pass # Handle setting the passwordThe router will recognize this decorator and automatically generate the detail route: /users/{pk}/set_password/.
Custom Routers
If you need a routing schema that is fundamentally different from the standard RESTful pattern, you can build a custom router by subclassing BaseRouter or SimpleRouter.
from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter):
"""
A router for read-only APIs, which doesn't use trailing slashes.
"""
routes = [
Route(
url=r'^{prefix}$',
mapping={'get': 'list'},
name='{basename}-list',
detail=False,
initkwargs={'suffix': 'List'}
),
Route(
url=r'^{prefix}/{lookup}$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
detail=True,
initkwargs={'suffix': 'Detail'}
),
DynamicRoute(
url=r'^{prefix}/{lookup}/{url_path}$',
name='{basename}-{url_name}',
detail=True,
initkwargs={}
)
]Custom routers allow you to explicitly define how your viewset actions map to HTTP methods and URL patterns, bypassing DRF's defaults completely.
