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

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

python 复制代码
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:

python 复制代码
urlpatterns = [
    path('users/', UserList.as_view()),
    path('users/<int:pk>/', UserDetail.as_view()),
]

但是在 DRF 中,一个 ViewSet 通常包含了 list/create/retrieve/update/destroy 等多个动作。

如果手写 URL 映射会非常繁琐。

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


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

以 DefaultRouter 为例,调用 register() 时:

python 复制代码
router.register(r'users', UserViewSet)

主要做了三件事:

  1. 保存注册信息

    把 prefix='users' 和 viewset=UserViewSet 存入 self.registry 列表中。

    python 复制代码
    self.registry.append((prefix, viewset, basename))
  2. 确定 basename

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

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

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


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

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

  1. 遍历 self.registry 中的所有注册项

    每个项包含:prefix、viewset、basename

  2. 调用 get_urls()

    根据 ViewSet 的动作方法(list、create、retrieve、update、partial_update、destroy)生成对应的路由规则。

    例如 UserViewSet 默认生成:

    URL HTTP方法 动作
    /users/ GET list
    /users/ POST create
    /users/{pk}/ GET retrieve
    /users/{pk}/ PUT update
    /users/{pk}/ PATCH partial_update
    /users/{pk}/ DELETE destroy
  3. 拼接为最终的 urlpatterns

    这就是 router.urls 的来源,最终交给 Django 的 URLConf 系统使用。


4. DefaultRouter 和 SimpleRouter 的区别

  • SimpleRouter

    只生成 CRUD 的基础路由。

  • DefaultRouter

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

示例:

访问 /api/,会看到:

python 复制代码
{
  "users": "http://127.0.0.1:8000/api/users/",
  "groups": "http://127.0.0.1:8000/api/groups/"
}

5. 自定义 Router

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

python 复制代码
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() 负责登记 prefix、viewset、basename,并保存到 self.registry。

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

  • DefaultRouter 比 SimpleRouter 多了一个根 API 入口。

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

相关推荐
weixin_BYSJ19872 天前
【计算机毕设】基于Spring_Boot_Vue的马拉松报名与选手成绩追踪系统05445
java·vue.js·spring boot·学习·spring·django·课程设计
小马不起床3 天前
Django 后端实战指南_10:用户扩展档案信息表
python·django·sqlite
小马不起床3 天前
Django 后端实战指南_9:前后端完整联调和问题修复
python·django·状态模式
ycydynq3 天前
django用Bootstrap 模态框 在同一页面实现增删改查
django·bootstrap·jquery
雪域迷影4 天前
Python Django 7 小时课程
开发语言·python·django
Wx-bishekaifayuan4 天前
springboot铜仁非遗之家76938-计算机课程设计、毕业设计
java·spring boot·后端·spring·django·课程设计·旅游
VidDown4 天前
上线三个月后的第一次事故:一个 Django 服务的日志、监控与故障复盘
数据库·python·django·wpf·音视频·视频编解码
小马不起床4 天前
Django 后端实战指南_5:实现 JWT 登录
python·django·sqlite
CarIise4 天前
Maven依赖传递与聚合工程
python·r语言·django
ycydynq4 天前
djiango引入django-ckeditor-5-0.2.20 modelform表单
django·django-ckeditor