2017-07-27 19 views
0

我已經看過幾個類似於這個問題的帖子,但沒有一個解決了我的問題。Django Rest Framework - 根據權限返回用戶或具有ModelViewSet的單個用戶列表

我正在使用Django Rest Framework的ModelViewSet。我有兩個視圖,一個詳細視圖和一個列表視圖。

我想要它,所以如果超級用戶訪問我的列表視圖,他會得到所有的用戶。如果普通用戶訪問列表視圖,他只能看到自己。

如果超級用戶訪問詳細視圖,他可以查看任何用戶。如果普通用戶訪問不是他的詳細視圖,他會得到一個認證錯誤。

我第一次嘗試使用權限,但意識到使用列表視圖的所有查詢集has_object_permission不運行,允許經過身份驗證的非超級用戶查看每個人。這是因爲對象權限只能用get命令運行。我試圖只覆蓋get_object,但get_object不被調用列表視圖,所以它沒有區別。所以我試圖覆蓋get_quertyset沒有get_objects,但這打破了我的細節視圖。

我的理解是,首先調用get_object作爲詳細視圖,然後調用get_queryset,如果我不覆蓋它們中的任何一個。但是,如果我重寫get_queryset,它會打破我的詳細信息視圖和get_object的正常功能(它不會基於主鍵進行篩選)。幕後必然會出現比我看到的更多的事情。必須有一種方法來編寫get_queryset來解決這個問題,即正常的Django版本,我不這樣做。

所以下面是我實現哪些工作,但我不明白爲什麼我必須重寫get_object。如果我只覆蓋get_queryset,那麼詳細信息視圖將被破壞,並以超級用戶身份登錄時返回所有用戶,而不是基於主鍵過濾的一個用戶。有沒有辦法來覆蓋get_queryset沒有get_object來解決這種行爲?

瀏覽:

class UserViewSet(viewsets.ModelViewSet): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 
    permission_classes = (AllowPostAnyReadAuthenticatedUser,) 

    def get_queryset(self): 
     user = self.request.user 
     if user.is_superuser: 
      return User.objects.all() 
     return User.objects.filter(username=user.username) 

    def get_object(self): 
     obj = get_object_or_404(User.objects.filter(id=self.kwargs["pk"])) 
     self.check_object_permissions(self.request, obj) 
     return obj 

權限:

class AllowPostAnyReadAuthenticatedUser(permissions.BasePermission): 

    def has_permission(self, request, view): 
     # Allow anyone to register 
     if request.method == "POST": 
      return True 
     # Must be authenticated to view 
     else: 
      return request.user and is_authenticated(request.user) 

    def has_object_permission(self, request, view, obj): 
     # Any view method requires you to be the user 
     return obj.id == request.user.id or request.user.is_superuser 

串行:

class UserSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = User 
     fields = ('username', 'email', 'id', 'password') 
     read_only_fields = ('id',) 
     extra_kwargs = { 
      'password': {'write_only': True} 
     } 

網址:

userList = views.UserViewSet.as_view({ 
    'get': 'list', 
    'post': 'create' 
}) 

userDetail = views.UserViewSet.as_view({ 
    'get': 'retrieve', 
    'put': 'update', 
    'patch': 'partial_update', 
    'delete': 'destroy' 
}) 

urlpatterns = [ 
    url(r'^$', userList, name='users'), 
    url(r'^(?P<pk>\d+)$', userDetail, name='user'), 
] 

回答

1

你正在做這個正確的!你不需要重寫你的視圖上的get_object方法,但是,ModelViewSet checks your permissions in get_object

+0

感謝您的迴應!如果我不覆蓋get_object,並且我是超級用戶,那麼由get_object調用的queryset將返回所有用戶,而不是與主鍵匹配的用戶(因爲覆蓋get_queryset將返回全部4個)。我不確定如何使get_queryset的行爲不同,如果它是一個詳細視圖與列表視圖(或者如果有一個pk列出vs不是)。所以detail_view會得到4個響應,這會導致錯誤。 – Diesel