2016-11-06 74 views
7

我創建2個ModelViewSets像這樣(簡化演示):在DRF嵌套視圖集中路線

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_routeSomeBaseViewSet,但不能找出「正確」的方式將其連接到我的AdminViewSet
  • 添加url(r'^api/some_view/admin$', AdminViewSet.as_view({"get": "list"}))到我的URL模式(這八九不離十工作,但neuters的ViewSet有點,而且通常真的是手動的):
  • some_view的視圖設置了專用的DefaultRouter,然後我在url(r'^api/some_view/')上掛載 - 再次哈克和迂腐處理大量路線

有沒有一種「正確」的方式來做我想要完成的事情,或者我應該爲這個問題找到一個不同的解決方案。過濾器或其他)?

我見過像https://github.com/alanjds/drf-nested-routers這樣的圖書館,但對我的(相當簡單的)需求來說,這看起來像是過度殺傷性的。

回答

1

我想我已經找到了自己的問題的答案,但是我在這個上面加了+50代表賞金以防萬一有人想要參加(@ tom-christie也許?)。

無論哪種方式,我已經解決了我的用例是通過使用@list_routeAdminViewSet.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 

,並讓一個有網址的相應路由(基於函數的名稱),並執行所需的任何額外的東西。

+0

我覺得你濫用as_view。在他們的文檔as_view似乎是一個URL配置功能。此外,如果您決定將管理操作擴展到更多視圖,則必須編寫更多代碼。我將發佈我的建議解決方案 – Dap

+0

我想'as_view'的評估應該移出'admin'列表路線,否則對我來說這似乎不是一個壞主意。 – dhill

1

很好的問題。我會爲此查看DRF的detail_route - 這是我過去成功使用的一種成語,用於創建一個掛起視圖集的一次性端點類型。 HTH,

http://www.django-rest-framework.org/api-guide/routers/#extra-link-and-actions

+0

'@ list_route'在這裏更適合我的用例(正如我在上面的回答中所述),因爲它不需要PK,也不需要。還是)感謝你的建議! – Fitblip

+0

@Fitblip你絕對是對的 - detail_route確實需要PK,所以在這裏沒有用處。我很欣賞這個更正。 –

+0

我很欣賞迴應!這個問題有點像鬼城 – Fitblip

3

使用列表路由定義你的管理視圖集。這些參數將允許您執行一個獲取請求,並具有指定的權限(經過身份驗證並具有管理員權限),從而擴展此類。即/someview/adminsomeotherview/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參考不會與您的詳細路線衝突。

0

不知道如果我錯過了什麼,但我剛剛測試,這個完美的作品(順序很重要):

router = DefaultRouter() 
# this will overrides routes from the line below 
router.register(r'some_view/admin', AdminViewSet) 
router.register(r'some_view', SomeBaseViewSet)