路由器
资源路由允许你快速声明给定资源控制器的所有常见路由。无需为你的索引声明单独的路由...资源路由在单行代码中声明它们。
一些 Web 框架(如 Rails)提供功能,用于自动确定如何将应用程序的 URL 映射到处理传入请求的逻辑。
REST 框架为 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.urls
register()
方法有两个必需参数
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)),
]
您可以将 include
与应用程序命名空间一起使用
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 框架视图进行命名空间处理。
额外操作的路由
视图集可以通过使用 @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'
API 指南
SimpleRouter
此路由器包含标准 list
、create
、retrieve
、update
、partial_update
和 destroy
操作的路由。视图集还可以使用 @action
装饰器标记要路由的其他方法。
URL 样式 | HTTP 方法 | 操作 | URL 名称 |
---|---|---|---|
{prefix}/ | 获取 | 列表 | {basename}-列表 |
发布 | 创建 | ||
{prefix}/{url_path}/ | 获取,或由 `methods` 参数指定 | `@action(detail=False)` 修饰的方法 | {basename}-{url_name} |
{prefix}/{lookup}/ | 获取 | 检索 | {basename}-详情 |
更新 | 更新 | ||
补丁 | 部分更新 | ||
删除 | 销毁 | ||
{prefix}/{lookup}/{url_path}/ | 获取,或由 `methods` 参数指定 | `@action(detail=True)` 修饰的方法 | {basename}-{url_name} |
默认情况下,SimpleRouter
创建的 URL 会附加一个尾部斜杠。可以在实例化路由器时将 trailing_slash
参数设置为 False
来修改此行为。例如
router = SimpleRouter(trailing_slash=False)
尾部斜杠在 Django 中是惯例,但在 Rails 等其他一些框架中默认不使用。选择哪种样式在很大程度上取决于个人喜好,尽管一些 javascript 框架可能需要特定的路由样式。
默认情况下,SimpleRouter
创建的 URL 使用正则表达式。可以在实例化路由器时将 use_regex_path
参数设置为 False
来修改此行为,在这种情况下,路径转换器被使用。例如
router = SimpleRouter(use_regex_path=False)
注意:use_regex_path=False
仅适用于 Django 2.x 或更高版本,因为此功能是在 2.0.0 中引入的。请参阅发行说明
路由器将匹配包含除斜杠和句点字符之外的任何字符的查找值。对于更严格(或宽松)的查找模式,请在使用路径转换器时在视图集或 lookup_value_converter
上设置 lookup_value_regex
属性。例如,您可以将查找限制为有效的 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'
DefaultRouter
此路由器与上述 SimpleRouter
类似,但另外包含一个默认 API 根视图,该视图返回一个包含指向所有列表视图的超链接的响应。它还为可选的 .json
样式格式后缀生成路由。
URL 样式 | HTTP 方法 | 操作 | URL 名称 |
---|---|---|---|
[.format] | 获取 | 自动生成的根视图 | api-root |
{prefix}/[.format] | 获取 | 列表 | {basename}-列表 |
发布 | 创建 | ||
{prefix}/{url_path}/[.format] | 获取,或由 `methods` 参数指定 | `@action(detail=False)` 修饰的方法 | {basename}-{url_name} |
{prefix}/{lookup}/[.format] | 获取 | 检索 | {basename}-详情 |
更新 | 更新 | ||
补丁 | 部分更新 | ||
删除 | 销毁 | ||
{prefix}/{lookup}/{url_path}/[.format] | 获取,或由 `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:URL 在 reverse
调用中使用的名称。可能包括以下格式字符串
{basename}
- 用于创建的 URL 名称的基础。
initkwargs:实例化视图时应传递的任何其他参数的字典。请注意,detail
、basename
和 suffix
参数保留用于视图集自省,并且还由可浏览 API 用于生成视图名称和面包屑链接。
自定义动态路由
您还可以自定义 @action
装饰器的路由方式。在 .routes
列表中包含 DynamicRoute
命名元组,根据基于列表的路由和基于详细信息的路由设置 detail
参数。除了 detail
之外,DynamicRoute
的参数还有
url:表示要路由的 URL 的字符串。可能包括与 Route
相同的格式字符串,此外还接受 {url_path}
格式字符串。
name:URL 在 reverse
调用中使用的名称。可能包括以下格式字符串
{basename}
- 用于创建的 URL 名称的基础。{url_name}
- 提供给@action
的url_name
。
initkwargs:实例化视图时应传递的任何其他参数的字典。
示例
以下示例仅路由到 list
和 retrieve
操作,并且不使用尾部斜杠约定。
from rest_framework.routers import Route, DynamicRoute, SimpleRouter
class CustomReadOnlyRouter(SimpleRouter):
"""
A router for read-only APIs, which doesn't use trailing slashes.
"""
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):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'
@action(detail=True)
def group_names(self, request, pk=None):
"""
Returns a list of all the group names that the given
user belongs to.
"""
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 | 获取 | 列表 | user-list |
/users/{username} | 获取 | 检索 | user-detail |
/users/{username}/group_names | 获取 | 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 类(和单例实例),该类使用 register_model()
API 扩展了 DefaultRouter
。与 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 扩展
DRF-extensions
软件包 提供了 路由器,用于创建 嵌套视图集、集合级别控制器,其中包含 可自定义的端点名称。