Skip to content

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.

python
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:

URLHTTP MethodAction
/users/GETlist()
/users/POSTcreate()
/users/{pk}/GETretrieve()
/users/{pk}/PUTupdate()
/users/{pk}/PATCHpartial_update()
/users/{pk}/DELETEdestroy()

The DefaultRouter

The DefaultRouter is identical to SimpleRouter, but it provides two additional benefits:

  1. It includes an automatic API root view that returns a dictionary mapping of all registered list views.
  2. It generates format suffix patterns (e.g., .json or .html) for all its routes natively, meaning you don't need to manually use format_suffix_patterns in your urls.py.
python
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:

python
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():

python
urlpatterns = [
    path('custom/', custom_view),
]

urlpatterns += router.urls

Extra Actions

If you have defined custom endpoints on your ViewSet using the @action decorator, routers will automatically generate URLs for them as well.

python
# 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 password

The 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.

python
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.