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 自动生成器,大大简化了手写路由的工作。

相关推荐
言乐615 小时前
Python排名统计折线图
开发语言·python·django·virtualenv·pygame
Wx-bishekaifayuan16 小时前
springboot户外登山社交小程序19787-计算机课程设计、毕业设计
spring boot·后端·python·spring·elasticsearch·django·课程设计
FYKJ_201016 小时前
springboot刑事案件管理系统03047-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
FYKJ_201017 小时前
springboot助农产品销售商城05829-计算机课程设计、毕业设计
java·spring boot·python·mysql·spark·django
Wx-bishekaifayuan18 小时前
springboot社区扶贫救助管理系统13300-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
Wx-bishekaifayuan20 小时前
springboot甘肃特产服务平台50301-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
FYKJ_201020 小时前
springboot雅集社区养老管理系统04456-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
FYKJ_201021 小时前
springboot羽毛球场地管理系统00626-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
Wx-bishekaifayuan21 小时前
django医院营收信息预测系统49414-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
Wx-bishekaifayuan21 小时前
springboot会议室预约管理系统42030-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游