资源路由允许你快速声明给定资源控制器的所有常见路由。与其分别声明各个路由,资源路由可在一行代码中完成。
— Ruby on Rails 文档
像 Rails 这样的 Web 框架提供了自动确定应用程序 URL 如何映射到处理传入请求逻辑的功能。
REST framework 为 Django 添加了对自动 URL 路由的支持,并为你提供了一种简单、快速且一致的方法,将视图逻辑连接到一组 URL。
使用方法
以下是使用 SimpleRouter 的简单 URL 配置示例。
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urlsregister() 方法有两个必需参数:
prefix- 此组路由使用的 URL 前缀。viewset- 视图集类。
另外,还可以指定一个额外参数:
basename- 创建的 URL 名称的基数。如果未设置,将根据视图集的queryset属性自动生成基数(如果有)。注意,如果视图集没有queryset属性,则注册视图集时必须设置basename。
上述示例将生成以下 URL 模式:
- URL 模式:
^users/$名称:'user-list' - URL 模式:
^users/{pk}/$名称:'user-detail' - URL 模式:
^accounts/$名称:'account-list' - URL 模式:
^accounts/{pk}/$名称:'account-detail' - *
注意 :basename 参数用于指定视图名称模式的初始部分。在上述示例中,即为 user 或 account 部分。
通常你不需要指定 basename 参数,但如果视图集定义了自定义 get_queryset 方法,则视图集可能未设置 .queryset 属性。如果尝试注册该视图集,你会看到类似以下错误:
'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.这意味着注册视图集时需要显式设置 basename 参数,因为无法从模型名称自动确定。
使用 include 与路由器结合
路由器实例上的 .urls 属性只是一个标准的 URL 模式列表。你可以采用多种方式包含这些 URL。
例如,可以将 router.urls 添加到现有视图列表中...
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
]
urlpatterns += router.urls或者可以使用 Django 的 include 函数,如下所示...
urlpatterns = [
path('forgot-password', ForgotPasswordFormView.as_view()),
path('', include(router.urls)),
]你还可以使用应用命名空间:
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'))),
]或者同时使用应用命名空间和实例命名空间:
urlpatterns = [
path('forgot-password/', ForgotPasswordFormView.as_view()),
path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]有关更多详细信息,请参阅 Django 的 URL 命名空间文档和 include API 参考。
注意 :如果在超链接序列化器中使用命名空间,则还需要确保序列化器上的任何 view_name 参数正确反映命名空间。在上述示例中,对于超链接到用户详情视图的序列化器字段,你需要包含类似 view_name='app_name:user-detail' 的参数。
自动 view_name 生成使用类似 %(model_name)-detail 的模式。除非你的模型名称确实存在冲突,否则在使用超链接序列化器时,最好 不要 为 Django REST Framework 视图设置命名空间。
视图集可以通过使用 @action 装饰器标记额外的操作以供路由使用。这些额外操作将包含在生成的路由中。例如,假设 UserViewSet 类上有 set_password 方法:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action
class UserViewSet(ModelViewSet):
...
@action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...将生成以下路由:
- URL 模式:
^users/{pk}/set_password/$ - URL 名称:
'user-set-password'
默认情况下,URL 模式基于方法名称,URL 名称是 ViewSet.basename 和连字符化方法名称的组合。
如果你不想使用这两个值的默认设置,可以改而向 @action 装饰器提供 url_path 和 url_name 参数。
例如,如果你希望将自定义操作的 URL 更改为 ^users/{pk}/change-password/$,你可以这样写:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action
class UserViewSet(ModelViewSet):
...
@action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
url_path='change-password', url_name='change_password')
def set_password(self, request, pk=None):
...现在将生成以下 URL 模式:
- URL 路径:
^users/{pk}/change-password/$ - URL 名称:
'user-change_password'
使用 Django path() 与路由器结合
默认情况下,路由器创建的 URL 使用正则表达式。可以通过在实例化路由器时将 use_regex_path 参数设置为 False 来修改此行为,此时将使用路径转换器。例如:
router = SimpleRouter(use_regex_path=False)路由器将匹配包含除斜杠和句点字符外的任何字符的查找值。要使用更严格的(或更宽松的)查找模式,可以在视图集上设置 lookup_value_regex 属性或 lookup_value_converter(如果使用路径转换器)。例如,你可以将查找限制为有效的 UUID:
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'
class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'注意,路径转换器将用于路由器中注册的所有 URL,包括视图集操作。
API 指南
SimpleRouter
此路由器为标准的 list、create、retrieve、update、partial_update 和 destroy 操作包含路由。视图集还可以使用 @action 装饰器标记额外的方法以供路由使用。
| URL 样式 | HTTP 方法 | 操作 | URL 名称 |
|---|---|---|---|
| {prefix}/ | GET | list | {basename}-list |
| POST | create | ||
| {prefix}/{url_path}/ | GET,或由 methods 参数指定 | 使用 @action(detail=False) 装饰的方法 | {basename}-{url_name} |
| {prefix}/{lookup}/ | GET | retrieve | {basename}-detail |
| PUT | update | ||
| PATCH | partial_update | ||
| DELETE | destroy | ||
| {prefix}/{lookup}/{url_path}/ | GET,或由 methods 参数指定 | 使用 @action(detail=True) 装饰的方法 | {basename}-{url_name} |
默认情况下,SimpleRouter 创建的 URL 会添加尾部斜杠。
可以通过在实例化路由器时将 trailing_slash 参数设置为 False 来修改此行为。例如:
router = SimpleRouter(trailing_slash=False)尾部斜杠在 Django 中是惯例,但在 Rails 等其他框架中并非默认使用。选择哪种风格主要取决于个人偏好,尽管某些 JavaScript 框架可能期望特定的路由风格。
DefaultRouter
此路由器与上述的 SimpleRouter 类似,但额外包含一个默认的 API 根视图,该视图返回包含指向所有列表视图的超链接的响应。它还会为可选的 .json 样式格式后缀生成路由。
| URL 样式 | HTTP 方法 | 操作 | URL 名称 |
|---|---|---|---|
| [.format] | GET | 自动生成的根视图 | api-root |
| {prefix}/[.format] | GET | list | {basename}-list |
| POST | create | ||
| {prefix}/{url_path}/[.format] | GET,或由 methods 参数指定 | 使用 @action(detail=False) 装饰的方法 | {basename}-{url_name} |
| {prefix}/{lookup}/[.format] | GET | retrieve | {basename}-detail |
| PUT | update | ||
| PATCH | partial_update | ||
| DELETE | destroy | ||
| {prefix}/{lookup}/{url_path}/[.format] | GET,或由 methods 参数指定 | 使用 @action(detail=True) 装饰的方法 | {basename}-{url_name} |
与 SimpleRouter 一样,可以通过在实例化路由器时将 trailing_slash 参数设置为 False 来移除 URL 路由中的尾部斜杠。
router = DefaultRouter(trailing_slash=False)自定义路由器
实现自定义路由器并不是你经常需要做的事情,但如果对 API 的 URL 结构有特定要求,则可能会很有用。这样做可以将 URL 结构封装在一个可重用的方式中,确保你不必为每个新视图显式编写 URL 模式。
实现自定义路由器的最简单方法是子类化现有的路由器类之一。.routes 属性用于模板化将映射到每个视图集的 URL 模式。.routes 属性是一个 Route 命名元组列表。
Route 命名元组的参数如下:
url:表示要路由的 URL 的字符串。可以包含以下格式字符串:
{prefix}- 此组路由使用的 URL 前缀。{lookup}- 用于匹配单个实例的查找字段。{trailing_slash}- 根据trailing_slash参数是 '/' 还是空字符串。
mapping:HTTP 方法名称到视图方法的映射
name:在 reverse 调用中使用的 URL 名称。可以包含以下格式字符串:
{basename}- 创建的 URL 名称的基数。
initkwargs:实例化视图时传递的任何额外参数的字典。注意 detail、basename 和 suffix 参数保留用于视图集内省,也用于可浏览 API 生成视图名称和面包屑链接。
自定义动态路由
你还可以自定义 @action 装饰器的路由方式。在 .routes 列表中包含 DynamicRoute 命名元组,并根据需要将 detail 参数设置为列表或详情路由。除了 detail,DynamicRoute 的参数还有:
url:表示要路由的 URL 的字符串。可以包含与 Route 相同的格式字符串,并额外接受 {url_path} 格式字符串。
name:在 reverse 调用中使用的 URL 名称。可以包含以下格式字符串:
{basename}- 创建的 URL 名称的基数。{url_name}- 提供给@action的url_name。
initkwargs:实例化视图时传递的任何额外参数的字典。
示例
以下示例仅路由到 list 和 retrieve 操作,并且不使用尾部斜杠约定。
from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter):
"""
用于只读 API 的路由器,不使用尾部斜杠。
"""
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={}
)
]让我们看一下我们的 CustomReadOnlyRouter 为简单视图集生成的路由。
views.py:
class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
提供标准操作的视图集
"""
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
@action(detail=True)
def group_names(self, request, pk=None):
"""
返回给定用户所属的所有组名列表。
"""
user = self.get_object()
groups = user.groups.all()
return Response([group.name for group in groups])urls.py:
router = CustomReadOnlyRouter()
router.register('users', UserViewSet)
urlpatterns = router.urls将生成以下映射...
| URL | HTTP 方法 | 操作 | URL 名称 |
|---|---|---|---|
| /users | GET | list | user-list |
| /users/{username} | GET | retrieve | user-detail |
| /users/{username}/group_names | GET | group_names | user-group-names |
有关设置 .routes 属性的另一个示例,请参阅 SimpleRouter 类的源代码。
高级自定义路由器
如果你想要提供完全自定义的行为,可以覆盖 BaseRouter 并覆盖 get_urls(self) 方法。该方法应检查注册的视图集并返回 URL 模式列表。可以通过访问 self.registry 属性来检查注册的前缀、视图集和基名称元组。
你可能还需要覆盖 get_default_basename(self, viewset) 方法,或者在使用路由器注册视图集时始终显式设置 basename 参数。
第三方包
以下第三方包也已提供。
DRF 嵌套路由器
drf-nested-routers 包提供用于处理嵌套资源的路由器和关系字段。
ModelRouter (wq.db.rest)
wq.db 包提供了一个高级的 ModelRouter 类(和单例实例),它扩展了 DefaultRouter,并提供了 register_model() API。与 Django 的 admin.site.register 类似,rest.router.register_model 唯一必需的参数是模型类。可以从模型和全局配置中推断出合理的 url 前缀、序列化器和视图集默认值。
from wq.db import rest
from myapp.models import MyModel
rest.router.register_model(MyModel)DRF-extensions
DRF-extensions 包提供了用于创建嵌套视图集、具有可自定义端点名称的集合级别控制器的路由器。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。