代码改变世界

Django REST Framework (DRF) Router 注册流程详解 - 实践

2025-09-29 19:32  tlnshuju  阅读(20)  评论(0)    收藏  举报

在使用 Django REST Framework (DRF) 开发 API 的时候,我们常常会看到这样的代码:

from rest_framework.routers import DefaultRouter
from .views import UserViewSet, GroupViewSet
router = DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'groups', GroupViewSet)
urlpatterns = router.urls

只需要几行代码,就能自动生成 users/groups/ 的路由。
那么问题来了:

  • Router.register() 做了什么?

  • 为什么只需要写 ViewSet 就能生成一堆路由?

  • router.urls 是怎么来的?

本文将深入解析 DRF Router 的注册流程。


1. Router 的作用

在 Django 原生路由中,我们需要手动写 URL:

urlpatterns = [
    path('users/', UserList.as_view()),
    path('users//', UserDetail.as_view()),
]

但是在 DRF 中,一个 ViewSet 通常包含了 list/create/retrieve/update/destroy 等多个动作。
如果手写 URL 映射会非常繁琐。

于是,Router 的职责就是:根据 ViewSet 自动生成标准化的 URLConf


2. Router.register() 做了什么?

DefaultRouter 为例,调用 register() 时:

router.register(r'users', UserViewSet)

主要做了三件事:

  1. 保存注册信息
    prefix='users'viewset=UserViewSet 存入 self.registry 列表中。

    self.registry.append((prefix, viewset, basename))

  2. 确定 basename

    • 如果没指定,会自动从 UserViewSet.queryset.model 推断模型名称(如 user)。

    • 这个 basename 决定了路由命名空间,例如:user-listuser-detail

  3. 延迟生成 URL
    register() 并不会立刻生成 URL,而是等待访问 router.urls 时再统一构建。


3. router.urls 是怎么生成的?

当我们访问 router.urls 时,Router 会执行以下流程:

  1. 遍历 self.registry 中的所有注册项
    每个项包含:prefixviewsetbasename

  2. 调用 get_urls()
    根据 ViewSet 的动作方法(listcreateretrieveupdatepartial_updatedestroy)生成对应的路由规则。

    例如 UserViewSet 默认生成:

    URLHTTP方法动作
    /users/GETlist
    /users/POSTcreate
    /users/{pk}/GETretrieve
    /users/{pk}/PUTupdate
    /users/{pk}/PATCHpartial_update
    /users/{pk}/DELETEdestroy
  3. 拼接为最终的 urlpatterns
    这就是 router.urls 的来源,最终交给 Django 的 URLConf 系统使用。


4. DefaultRouter 和 SimpleRouter 的区别

  • SimpleRouter
    只生成 CRUD 的基础路由。

  • DefaultRouter
    除了 CRUD 路由,还会额外生成一个 根 API 页面api-root/),列出所有注册的资源入口。

示例:
访问 /api/,会看到:

{
  "users": "http://127.0.0.1:8000/api/users/",
  "groups": "http://127.0.0.1:8000/api/groups/"
}

5. 自定义 Router

如果你需要定制路由规则,可以继承 SimpleRouter 并重写 routes 属性:

from rest_framework.routers import SimpleRouter, Route
class CustomRouter(SimpleRouter):
    routes = [
        Route(
            url=r'^{prefix}/custom/{lookup}{trailing_slash}$',
            mapping={'get': 'custom_action'},
            name='{basename}-custom',
            detail=True,
            initkwargs={'suffix': 'Custom'}
        ),
    ]

这样就可以为所有 ViewSet 自动添加一个自定义路由。


6. 总结

  • register() 负责登记 prefixviewsetbasename,并保存到 self.registry

  • router.urls 在第一次访问时动态生成 URLConf,映射到 ViewSet 的标准动作。

  • DefaultRouterSimpleRouter 多了一个根 API 入口。

  • Router 本质上就是一个 URL 自动生成器,大大简化了手写路由的工作。