Routing APIs with DRF0%

Routing APIs with DRF

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Routing APIs with DRF

When working with Django REST Framework ViewSets, manually writing individual path() entries for every CRUD endpoint (list, create, retrieve, update, destroy) is tedious and error-prone. DRF Routers automatically generate standardized, consistent RESTful URL routing schemes, including trailing slash management and the browsable API root.


1. How DRF Routers Work

A DRF router inspects a ViewSet and automatically generates the complete set of standard REST URL patterns:

Output
ArticleViewSet registered at 'articles':
GET /api/v1/articles/ ──► ArticleViewSet.list()
POST /api/v1/articles/ ──► ArticleViewSet.create()
GET /api/v1/articles/{slug}/ ──► ArticleViewSet.retrieve()
PUT /api/v1/articles/{slug}/ ──► ArticleViewSet.update()
PATCH /api/v1/articles/{slug}/ ──► ArticleViewSet.partial_update()
DELETE /api/v1/articles/{slug}/ ──► ArticleViewSet.destroy()

2. Configuring DefaultRouter vs SimpleRouter

DRF provides two main router classes:

  • SimpleRouter: Generates only the basic CRUD URL patterns.
  • DefaultRouter: Extends SimpleRouter by adding a default API Root endpoint displaying hyperlinks to all registered resources, as well as optional .json / format suffix patterns.
Python
# articles/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet, CategoryViewSet
 
# 1. Instantiate the router
router = DefaultRouter()
 
# 2. Register viewsets with URL prefixes
router.register(r"articles", ArticleViewSet, basename="article")
router.register(r"categories", CategoryViewSet, basename="category")
 
# 3. Include router.urls in urlpatterns
app_name = "articles_api"
 
urlpatterns = [
path("", include(router.urls)),
]

Visiting http://127.0.0.1:8000/api/v1/ renders DRF's interactive Browsable API Root with clickable links to /articles/ and /categories/!


3. When is basename Required?

If a ViewSet has a queryset attribute, DRF automatically derives the basename from the model name:

Python
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all() # DRF automatically uses basename="article"

However, if your ViewSet overrides get_queryset() and omits the static queryset attribute, you must specify basename:

Python
router.register(r"my-articles", MyArticlesViewSet, basename="my-article")

4. Nested Routers with drf-nested-routers

For hierarchical REST APIs (e.g. /articles/{article_id}/comments/{comment_id}/), use the drf-nested-routers package:

Python
from rest_framework_nested import routers
from .views import ArticleViewSet, CommentViewSet
 
# Parent router
router = routers.SimpleRouter()
router.register(r"articles", ArticleViewSet)
 
# Nested child router
articles_router = routers.NestedSimpleRouter(router, r"articles", lookup="article")
articles_router.register(r"comments", CommentViewSet, basename="article-comments")
 
urlpatterns = [
path("", include(router.urls)),
path("", include(articles_router.urls)),
]

Interactive Quiz

Practice Quiz

Question 1
What is the primary advantage of using DRF Routers with ViewSets?
Question 2
What extra feature does DefaultRouter offer over SimpleRouter?
Question 3
When is the basename parameter strictly mandatory when calling router.register()?
Question 4
How does DRF's router construct the named URL for a retrieve action on a viewset registered with basename="article"?
Question 5
What package provides clean URL routing for nested endpoints like /articles/{id}/comments/?
Next Lesson

Custom Middleware

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Previous LessonNext Lesson
APIView & ViewSetCustom Middleware

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext