[英]Django, Custom action functions in GenericViewSet or Viewset
[英]how to reverse the URL of a ViewSet's custom action in django restframework
我為 ViewSet 定義了一個自定義操作
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
@action(methods=['get'], detail=False, permission_classes=[permissions.AllowAny])
def gender(self, request):
....
並且viewset以常規方式注冊到url
from django.conf.urls import url, include
from rest_framework import routers
from api import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet, base_name='myuser')
urlpatterns = [
url(r'^', include(router.urls)),
]
URL /api/users/gender/
有效。 但我不知道如何在單元測試中使用reverse
來獲得它。 (我當然可以對這個 URL 進行硬編碼,但是從代碼中得到它會很好)
根據django 文檔,以下代碼應該可以工作
reverse('admin:app_list', kwargs={'app_label': 'auth'})
# '/admin/auth/'
但是我嘗試了以下方法,但它們不起作用
reverse('myuser-list', kwargs={'app_label':'gender'})
# errors out
reverse('myuser-list', args=('gender',))
# '/api/users.gender'
在django-restframework 文檔中,有一個名為reverse_action
的 function 。 但是,我的嘗試沒有奏效
from api.views import UserViewSet
a = UserViewSet()
a.reverse_action('gender') # error out
from django.http import HttpRequest
req = HttpRequest()
req.method = 'GET'
a.reverse_action('gender', request=req) # still error out
扭轉該動作的 URL 的正確方法是什么?
您可以在啟動時使用get_urls()
方法打印給定router
所有可逆 url 名稱
在將最后一項注冊到router = DefaultRouter()
變量后的 urls.py 中,您可以添加:
#router = routers.DefaultRouter()
#router.register(r'users', UserViewSet)
#...
import pprint
pprint.pprint(router.get_urls())
下次您的應用程序初始化時,它將打印到標准輸出,例如
[<RegexURLPattern user-list ^users/$>,
<RegexURLPattern user-list ^users\.(?P<format>[a-z0-9]+)/?$>,
<RegexURLPattern user-detail ^users/(?P<pk>[^/.]+)/$>,
<RegexURLPattern user-detail ^users/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$>,
#...
]
其中 'user-list' 和 'user-detail' 是可以給reverse(...)
基於DRF 文檔。
from rest_framework import routers
router = routers.DefaultRouter()
view = UserViewSet()
view.basename = router.get_default_basename(UserViewSet)
view.request = None
或者您可以根據需要設置請求。
view.request = req
最后,您可以獲得一個反向操作 URL 並使用它。
url = view.reverse_action('gender', args=[])
如果你想特別使用UserViewset().reverse_action()
,你可以通過為你的 ViewSet 分配一個basename
和request = None
來做到這一點:
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
basename = 'user'
request = None
@action(methods=['get'], detail=False, permission_classes=[permissions.AllowAny])
def gender(self, request):
....
在 urls.py 中:
router.register('user', UserViewSet, basename=UserViewSet.basename)
然后調用url = UserViewset().reverse_action('gender')
或url = UserViewset().reverse_action(UserViewSet().gender.url_name)
將返回正確的 url。
編輯:上述方法僅在僅調用reverse_action()
一次時有效,因為ViewSetMixin.as_view()
方法在實例化時覆蓋basename
。 這可以通過添加的定制子類來解決GenericViewSet
(或ModelViewSet
如果優選的),如下所示:
from django.utils.decorators import classonlymethod
from rest_framework.viewsets import GenericViewSet
class ReversibleViewSet(GenericViewSet):
basename = None
request = None
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
basename = cls.basename
view = super().as_view(actions, **initkwargs)
cls.basename = basename
return view
並為特定的 ViewSet 子類化此類,根據需要設置 basename。
答案是reverse('myuser-gender')
。
筆記! 但請記住,DRF 會將動作名稱中的_
替換為-
。 這意味着如果動作名稱是my_pretty_action
反向你應該使用reverse(app-my-pretty-action)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.