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)),
]
eine GET-Anfrage an /api/mymodel/123/custom/ stellen
has_object_permission() sollte mit MyModel.objects.get(pk=123)
als Objekt aufgerufen werden.
Anfrage an die benutzerdefinierte Route in der Form /api/mymodel/123/custom/ ruft has_permission() in MyPermissions auf, aber nicht has_object_permission(), obwohl es sich um eine Detailroute handelt.
Wir müssen die Tatsache dokumentieren, dass Sie nur has_object_permission
aufgerufen bekommen, wenn Sie get_object
aufrufen.
Dies erscheint kontraintuitiv. Aufrufe wie /api/object/123/method/ werden im Allgemeinen verwendet, um eine Methode für die Objektinstanz mit der ID 123 aufzurufen, und es scheint, dass die Überprüfung der Objektberechtigung ein erwartetes Verhalten wäre. Andernfalls müsste jedes Mal, wenn jemand benutzerdefinierte Detailrouten erstellt, das Objekt abgerufen, die Berechtigungen manuell überprüft und fortgefahren werden. An diesem Punkt macht der Aufruf von has_object_permission() sowieso keinen Sinn. In jedem Szenario, in dem Berechtigungen auf Objektebene verwendet werden, müsste also eine solche Boilerplate verwendet werden
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
Ich glaube, ich habe es jetzt verstanden. Wenn ich get_object() in meinen benutzerdefinierten Routen aufrufe, wird has_object_permission() aufgerufen. Scheint immer noch kontraintuitiv, aber zumindest gibt es eine klare Lösung.
Ich würde gerne einen konkreten Pull-Request für die Dokumentation in Betracht ziehen, aber so wie es aussieht, denke ich, dass das, was wir haben, in http://www.django-rest-framework.org/api-guide/permissions/ in etwa angemessen ist.
Abschließend _könnten_, wie bereits erwähnt, spezifische Umformulierungen/Ergänzungen in Betracht gezogen werden.
Hilfreichster Kommentar
Wir müssen die Tatsache dokumentieren, dass Sie nur
has_object_permission
aufgerufen bekommen, wenn Sieget_object
aufrufen.