class MyViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MySerializer
authentication_classes = (MyAuth, )
permission_classes = (MyPermissions, )
@detail_route(methods=["GET", ])
def custom(self, request, pk=None):
return Response('whatever')
from rest_framework import routers
router = routers.SimpleRouter()
router.register('mymodel', MyViewSet)
urlpatterns = [
url(r'^api/', include(router.urls)),
]
向 /api/mymodel/123/custom/ 发出 GET 请求
has_object_permission() 应该用MyModel.objects.get(pk=123)
作为对象来调用。
以 /api/mymodel/123/custom/ 形式对自定义路由的请求将调用 MyPermissions 中的 has_permission(),但不会调用 has_object_permission(),即使它是详细路由。
我们需要记录这样一个事实,即只有在调用get_object
才会调用has_object_permission
get_object
。
这似乎违反直觉。 像 /api/object/123/method/ 这样的调用通常用于调用 ID 为 123 的对象实例上的某些方法,并且检查对象权限似乎是一种预期行为。 否则,每次有人制作自定义详细路线时,他们都必须检索对象,手动检查权限并继续。 在这一点上,调用 has_object_permission() 无论如何都没有意义。 因此,在使用对象级别权限的每种情况下,都必须使用一些像这样的样板
class CustomPermission(BasePermission):
def has_permission(self, request, view):
"""we need to do all permission checking here, since has_object_permission() is not guaranteed to be called"""
if 'pk' in view.kwargs and view.kwargs['pk']:
obj = view.get_queryset()[0]
# check object permissions here
else:
# check model permissions here
def has_object_permission(self, request, view, obj):
""" nothing to do here, we already checked everything, so ignore """
return True
我想我现在明白了。 如果我在自定义路由中调用 get_object(),则会调用 has_object_permission()。 似乎仍然违反直觉,但至少有一个明确的解决方案。
我很乐意考虑对文档的具体拉取请求,但就目前而言,我认为我们在http://www.django-rest-framework.org/api-guide/permissions/ 中已经足够了
结束这个,但如前所述,可以考虑特定的改写/添加。
最有用的评论
我们需要记录这样一个事实,即只有在调用
get_object
才会调用has_object_permission
get_object
。