视图集上的detail_route不遵循对象级权限

时间:2015-10-31 21:17:04

标签: django-rest-framework

这是我的ViewSet:

class PageViewSet(viewsets.ModelViewSet):
    queryset = Page.objects.all()
    serializer_class = PageSerializer
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user, location=self.request.user.userextended.location)

    @detail_route(methods=['post'])
    def add(self, request, pk=None):
        try:
            page = Page.objects.get(pk=pk)
        except:
            content = {'Page': ['The page you are trying to add no longer exists.']}
            return Response(content, status=status.HTTP_400_BAD_REQUEST)

        page.users.add(request.user)

        return Response(status=status.HTTP_204_NO_CONTENT)

这是我的IsOwnerOrReadOnly权限:

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Allow only the owner (and admin) of the object to make changes (i.e. 
    do PUT, PATCH, DELETE and POST requests. A user is an
    owner of an object if the object has an attribute
    called owner and owner is == request.user. If the
    object is a User object or if the object does not have
    an owner attribute, then return object == request.user.
    """

    def has_permission(self, request, view):
        print('In permission')
        return True

    def has_object_permission(self, request, view, obj):
        print('In object level permission')
        if request.method in permissions.SAFE_METHODS:
            return True

        if request.user.is_staff:
            return True

        try:
            return obj.owner == request.user
        except: # if obj does not have an owner property (e.g. users don't

                # have owner properties).
            return obj == request.user

问题是,即使我不是网页的所有者,我也可以作为经过身份验证的用户发布到add-detail。当我执行发布请求时,它只会打印In permission两次,而不会打印In object level permission。我的问题是,因为它是detail_route并且显然正在使用{lookup}对象(请参见此处显示它正在使用对象:http://www.django-rest-framework.org/api-guide/routers/),为什么has_object_permission()来自权限类的函数不会被调用?为什么只调用常规has_permission()函数?

我希望有人链接到一个文档,该文档会验证即使是detail_route,也只会调用has_permission

编辑:这不是Django rest framework ignores has_object_permission的重复,因为我使用的是从GenericAPIView继承的ModelViewSet(如文档中所述:http://www.django-rest-framework.org/api-guide/viewsets/#modelviewset)。

1 个答案:

答案 0 :(得分:3)

this answer。存在一些差异,但重点是:check_object_permissions未被调用。

虽然您继承自ModelViewSet,但您未在get_object方法中使用add来检索该网页。 get_object调用check_object_permissions(不是路由器)进行检索,更新等,所以很明显它不会被调用。

要解决此问题,请执行以下操作:

class PageViewSet(viewsets.ModelViewSet):

    # ...    

    @detail_route(methods=['post'])
    def add(self, request, pk=None):
        page = self.get_object()
        page.users.add(request.user)

        return Response(status=status.HTTP_204_NO_CONTENT)

或者只是在实施的某个地方做self.check_object_permissions(page)