Django REST framework API 指南(1):請求
Django REST framework API 指南(2):響應
Django REST framework API 指南(3):檢視
Django REST framework API 指南(4):通用檢視
Django REST framework API 指南(5):檢視集
Django REST framework API 指南(6):路由
Django REST framework API 指南(7):解析
路由
一些 Web 框架(如 Rails)提供了一種能夠自動確定應用程式的 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.urls
複製程式碼
register()
方法有兩個必須引數:
prefix
- 設定這組路由的字首。viewset
- 設定對應的檢視集類。
或者,您也可以指定一個附加引數:
base_name
- 用於建立的 URL 名稱的基礎。如果未設定,將根據檢視集的queryset
屬性自動生成。請注意,如果檢視集不包含queryset
屬性,則在註冊檢視集時必須設定base_name
。
上面的例子會生成以下 URL 模式:
- URL pattern:
^users/$
Name:'user-list'
- URL pattern:
^users/{pk}/$
Name:'user-detail'
- URL pattern:
^accounts/$
Name:'account-list'
- URL pattern:
^accounts/{pk}/$
Name:'account-detail'
注意:
base_name
引數用於指定檢視名稱模式的初始部分。在上面的例子中,是user
或account
部分。
通常,您不需要指定 base_name
引數,但是如果您有一個檢視集定義了自定義 get_queryset
方法,那麼該檢視集可能沒有設定 .queryset
屬性。如果此時嘗試註冊該檢視,則會看到如下所示的錯誤:
'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
複製程式碼
'base_name'
引數未指定,並且無法自動確定檢視中的名稱,因為它沒有'.queryset'
屬性。
這時候就需要在註冊檢視集時顯式設定 base_name
引數,因為它無法從模型名稱中自動確定。
使用 include
與路由
路由例項上的 .urls
屬性是一個標準的 URL patterns。關於如何包含這些 URL,有許多不同的樣式。
例如,可以將 router.urls
附加到現有檢視的列表中...
router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = [
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
]
urlpatterns += router.urls
複製程式碼
另外,你也可以使用 Django 的 include
函式,比如...
urlpatterns = [
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
url(r'^', include(router.urls)),
]
複製程式碼
還可以設定 namespace。
urlpatterns = [
url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
url(r'^api/', include(router.urls, namespace='api')),
]
複製程式碼
如果對超連結序列化器使用名稱空間,則還需要確保序列化器上的任何 view_name
引數都能正確反映名稱空間。在上面的示例中,您需要為超連結到使用者詳細資訊檢視的序列化程式欄位包含諸如 view_name='api:user-detail'
之類的引數。
額外的連結和操作
用 @detail_route
或 @list_route
裝飾的 檢視上的任何方法 也將被路由。例如,在 UserViewSet
類中給出這樣的方法:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route
class UserViewSet(ModelViewSet):
...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...
複製程式碼
會生成以下URL模式:
- URL pattern:
^users/{pk}/set_password/$
Name:'user-set-password'
如果您不想使用預設生成的 URL 模式,則可以使用 url_path 引數對其進行自定義。
例如,如果您想將我們的自定義操作的URL更改為 ^users/{pk}/change-password/$
,則可以編寫:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route
class UserViewSet(ModelViewSet):
...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_path='change-password')
def set_password(self, request, pk=None):
...
複製程式碼
上面的例子現在將生成以下URL模式:
- URL pattern:
^users/{pk}/change-password/$
Name:'user-change-password'
如果您不想使用生成的預設名稱,則可以使用 url_name 引數對其進行自定義。
例如,如果您想將自定義操作的名稱更改為 'user-change-password'
,則可以編寫:
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route
class UserViewSet(ModelViewSet):
...
@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf], url_name='change-password')
def set_password(self, request, pk=None):
...
複製程式碼
上面的例子現在將生成以下URL模式:
- URL pattern:
^users/{pk}/set_password/$
Name:'user-change-password'
可以同時使用 url_path
和 url_name
引數。
更多相關資訊請看 檢視集:標記額外的路由行為。
API 參考
SimpleRouter
SimpleRouter
包含標準的 list
,create
,retrieve
,update
,partial_update
和 destroy
action。SimpleRouter
還支援檢視集使用 @detail_route
或 @list_route
裝飾器標記其他要路由的方法。
URL Style | HTTP Method | Action | URL Name |
---|---|---|---|
{prefix}/ | GET | list | {basename}-list |
POST | create | ||
{prefix}/{methodname}/ | GET, 或者由 `methods` 引數指定 | `@list_route` 裝飾的方法 | {basename}-{methodname} |
{prefix}/{lookup}/ | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{methodname}/ | GET, 或者由 `methods` 引數指定 | `@detail_route` 裝飾的方法 | {basename}-{methodname} |
預設情況下,由 SimpleRouter
建立的 URL 附加了尾部斜槓。在例項化路由器時,可以通過將 trailing_slash
引數設定為 False
來修改此行為。例如:
router = SimpleRouter(trailing_slash=False)
複製程式碼
尾部斜槓在 Django 中是常規的,但在其他一些框架(如 Rails)中預設不使用。選擇使用哪種風格在很大程度上是一個偏好問題,儘管一些 JavaScript 框架可能會期望特定的路由風格。
SimpleRouter
將匹配包含除斜槓和句點字元以外的任何字元的 lookup 值。對於更嚴格(或寬鬆)的 lookup pattern,請在檢視集上設定 lookup_value_regex
屬性。例如,您可以將 lookup 限制為有效的 UUID:
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'
複製程式碼
DefaultRouter
DefaultRouter
與上面的 SimpleRouter
相似,但還包含一個預設的 API 根檢視,該檢視返回一個包含指向所有列表檢視的超連結的響應。它還為可選的 .json
風格格式字尾生成路由。
URL Style | HTTP Method | Action | URL Name |
---|---|---|---|
[.format] | GET | 自動生成的根檢視 | api-root |
{prefix}/[.format] | GET | list | {basename}-list |
POST | create | ||
{prefix}/{methodname}/[.format] | GET, 或者由 `methods` 引數指定 | `@list_route` 裝飾的方法 | {basename}-{methodname} |
{prefix}/{lookup}/[.format] | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{methodname}/[.format] | GET, 或者由 `methods` 引數指定 | `@detail_route` 裝飾的方法 | {basename}-{methodname} |
注意:我在使用 3.7.7 版本時,發現要寫成
{prefix}[.format]/
風格才能訪問,{prefix}/[.format]
風格會報 404,不知道是我設定問題還是官方更新了。
與 SimpleRouter
一樣,通過在例項化 DefaultRouter
時將 trailing_slash
引數設定為 False
,可以刪除 URL 路徑上的尾部斜槓。
router = DefaultRouter(trailing_slash=False)
複製程式碼
自定義路由
自定義路由並不是你經常需要做的事情,但是如果你對 API 的 URL 是如何構建的有特定的要求的話,它會很有用。這樣做可以讓你以可重用的方式封裝 URL 結構,確保你不必為每個新檢視明確編寫 URL 模式。
實現自定義路由的最簡單方法是對現有路由類之一進行子類化。.routes
屬性用於對將對映到每個檢視集的 URL 模式進行模板化。.Routes
屬性是一個 Route
列表(Route
的是一個 namedtuple)。
Route
命名元組的引數:
url : 表示要路由的 URL 的字串。可以包含以下格式字串:
{prefix}
- 路由的 URL 字首。{lookup}
- 匹配單個例項的 lookup field。{trailing_slash}
- 可以是 '/' 或空字串,具體取決於trailing_slash
引數。
mapping : HTTP 方法名稱與檢視方法的對映
name: 用於呼叫 reverse
時的 URL 的名稱。可能包含以下格式字串:
{basename}
- 建立的 URL 名稱的基礎。
initkwargs: 例項化檢視時應傳遞的任何其他引數的字典。注意,suffix
引數被保留用於標識檢視集型別,在生成檢視名稱和 breadcrumb 連結時使用。
自定義動態路由
你還可以自定義 @list_route
和 @detail_route
裝飾器的路由方式。要路由這兩個裝飾器中的一個或兩個,請在 .routes
列表中包含一個 DynamicListRoute
和/或 DynamicDetailRoute
(別忘了型別是 namedtuple)。
DynamicListRoute
和 DynamicDetailRoute
的引數是:
url: 表示要路由的 URL 的字串。可以包含與 Route
相同的格式字串,並且還接受 {methodname}
和 {methodnamehyphen}
格式的字串。
name: 用於呼叫 reverse
時的名稱。可以包含以下格式字串:{basename}
, {methodname}
和 {methodnamehyphen}
。
initkwargs: 例項化檢視時應傳遞的任何其他引數的字典。
舉個例子
以下示例只會路由 list
和 retrieve
action,並且不使用尾部斜槓約定。
from rest_framework.routers import Route, DynamicDetailRoute, 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',
initkwargs={'suffix': 'List'}
),
Route(
url=r'^{prefix}/{lookup}$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
initkwargs={'suffix': 'Detail'}
),
DynamicDetailRoute(
url=r'^{prefix}/{lookup}/{methodnamehyphen}$',
name='{basename}-{methodnamehyphen}',
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'
@detail_route()
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 Method | Action | URL Name |
---|---|---|---|
/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
屬性來檢查註冊的 prefix,viewset 和 basename tuples。
你可能還想覆蓋 get_default_base_name(self,viewset)
方法,或者在向路由註冊檢視集時始終顯式設定 base_name
引數。
第三方軟體包
以下是可用的第三方包。