这是我的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)。
答案 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)
。