在DRF中嵌套ViewSet路由
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在DRF中嵌套ViewSet路由相关的知识,希望对你有一定的参考价值。
我已经创建了2个这样的ModelViewSets(简化为演示):
class SomeBaseViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = SomeEventSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
return SomeObjects.objects.filter(owner=self.request.user)
def get_serializer_context(self):
context = super(SomeBaseViewSet, self).get_serializer_context()
context.update({
"user": self.request.user,
"some_context_key": False
})
return context
class AdminViewSet(SomeBaseViewSet):
# Added in the HasAdminPermission
permission_classes = (permissions.IsAuthenticated, HasAdminPermission)
# Different queryset filter (overriding `get_queryset` vs setting queryset for standardization)
def get_queryset(self):
return SomeObjects.objects.all()
# The context should have `some_context_key=True`, and `user=request.user`
def get_serializer_context(self):
context = super(AdminViewSet, self).get_serializer_context()
context.update({
"some_context_key": True
})
return context
我的路由器/ url配置看起来像这样
router = DefaultRouter()
router.register(r'some_view', SomeBaseViewSet, base_name="some_view")
urlpatterns += [
url(r'^api/', include(router.urls)),
]
如果我想将/api/some_view/admin
路由到AdminViewSet,那么最好的方法是什么?
我试过的事情:
- 在
@list_route
上的SomeBaseViewSet
,但无法弄清楚将它连接到我的AdminViewSet
的“正确”方式 - 将
url(r'^api/some_view/admin$', AdminViewSet.as_view({"get": "list"}))
添加到我的urlpatterns(这种类型可以运行,但是ViewSet稍微适用一些,并且通常真的是手动的): - 有一个专用的
DefaultRouter
用于some_view
视图,然后我登上url(r'^api/some_view/')
- 再次hacky和迂腐与大量的路线
是否有一种“正确”的方式来完成我想要完成的任务,或者我应该找到针对此问题的不同解决方案(即过滤器或其他东西)?
我见过像https://github.com/alanjds/drf-nested-routers这样的图书馆,但这对我(相当简单)的需求来说似乎有些过分。
使用列表路径定义管理视图集。这些参数将允许您执行具有指定权限(经过身份验证并具有管理权限)的get请求,该请求扩展了此类。即/someview/admin
或someotherview/admin
from rest_framework.decorators import list_route
class AdminViewSet(viewset.Viewsets):
@list_route(methods=['get'],
permissions=[permissions.IsAuthenticated, HasAdminPermission],
url_path='admin'
)
def admin(self, request):
# All your custom logic in regards to querysets and serializing
return serialized.data
然后,您可以扩展需要管理操作路由的任何视图集。
class SomeBaseViewSet(viewsets.ReadOnlyModelViewSet, AdminViewset):
serializer_class = SomeEventSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
return SomeObjects.objects.filter(owner=self.request.user)
def get_serializer_context(self):
context = super(SomeBaseViewSet, self).get_serializer_context()
context.update({
"user": self.request.user,
"some_context_key": False
})
return context
你要小心这个,因为通常你的基本路线后面的参数,即/ someview / {param} /是为ID引用保留的。确保您的ID引用不会与您的详细路径冲突。
我想我已经找到了我自己的问题的答案,但是如果有人想要加入(@ tom-christie也许?),我会在这个问题上加上+50代表奖金。
无论哪种方式,我为我的用例解决它的方式是使用@list_route
和AdminViewSet
的.as_view()
函数。
这样的东西就足够了:
class SomeBaseViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = SomeEventSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
return SomeObjects.objects.filter(owner=self.request.user)
def get_serializer_context(self):
context = super(SomeBaseViewSet, self).get_serializer_context()
context.update({
"user": self.request.user,
"some_context_key": False
})
return context
@list_route()
def admin(self, request):
return AdminViewSet.as_view({"get": "list"})(request)
class AdminViewSet(SomeBaseViewSet):
# Added in the HasAdminPermission
permission_classes = (permissions.IsAuthenticated, HasAdminPermission)
# Different queryset filter (overriding `get_queryset` vs setting queryset for standardization)
def get_queryset(self):
return SomeObjects.objects.all()
# The context should have `some_context_key=True`, and `user=request.user`
def get_serializer_context(self):
context = super(AdminViewSet, self).get_serializer_context()
context.update({
"some_context_key": True
})
return context
并允许人们相应地路由URL(基于函数的名称),并强制执行您需要的任何额外的事情。
好问题。我为此检查了DRF的detail_route - 这是我过去成功使用的一个成语,用于创建一个挂起视图集的一次性端点。 HTH,
http://www.django-rest-framework.org/api-guide/routers/#extra-link-and-actions
不知道我是否错过了一些东西,但我刚刚测试过,这完美无缺(订单很重要):
router = DefaultRouter()
# this will overrides routes from the line below
router.register(r'some_view/admin', AdminViewSet)
router.register(r'some_view', SomeBaseViewSet)
以上是关于在DRF中嵌套ViewSet路由的主要内容,如果未能解决你的问题,请参考以下文章