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)),
]
hacer una solicitud GET a / api / mymodel / 123 / custom /
has_object_permission () debe llamarse con MyModel.objects.get(pk=123)
como objeto.
la solicitud a la ruta personalizada en forma de / api / mymodel / 123 / custom / llamará a has_permission () en MyPermissions, pero no a has_object_permission () aunque es una ruta detallada.
Necesitamos documentar el hecho de que solo recibirá la llamada has_object_permission
solo si llama a get_object
.
Esto parece contrario a la intuición. Las llamadas como / api / object / 123 / method / generalmente se usan para llamar a algún método en la instancia del objeto con ID 123 y parece que verificar el permiso del objeto sería un comportamiento esperado. De lo contrario, cada vez que alguien haga rutas detalladas personalizadas, tendría que recuperar el objeto, verificar manualmente los permisos y continuar. En ese punto, llamar a has_object_permission () no tiene sentido de todos modos. Entonces, en cada escenario donde se usan permisos a nivel de objeto, se tendría que usar un texto repetitivo como este
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
Creo que lo entiendo ahora. Si llamo a get_object () en mis rutas personalizadas, se llamará a has_object_permission (). Todavía parece contrario a la intuición, pero al menos hay una solución clara.
Me complacería considerar una solicitud de extracción concreta para la documentación, pero tal como está, creo que lo que tenemos es adecuado en http://www.django-rest-framework.org/api-guide/permissions/ #object -level -permissions
Cerrando esto, pero como se señaló, se podría considerar una reformulación / adiciones específicas.
Comentario más útil
Necesitamos documentar el hecho de que solo recibirá la llamada
has_object_permission
solo si llama aget_object
.