我的 Django 端点无法访问 has_object_permission 方法

My Django endpoint does not access the has_object_permission method

提问人:Mario Berg 提问时间:11/16/2023 更新时间:11/16/2023 访问量:19

问:

这是我有一个视图类:

from rest_framework.views import APIView
class MyView(APIView):
    permission_classes = [CustomAccessPermission]

    def get(self, request, id: int) -> Response:
        object = get_object_or_404(MyObjectClass, id)
        serializer = MySerializer(object)
        return Response(serializer.data)

    def delete(self, request, id: int):
        object = get_object_or_404(MyObjectClass, id)
        object.status = MyObjectClass.Status.DELETED
        object.save()
        return Response(status=status.HTTP_200_OK, data=id)

这是我的自定义访问权限类:

from rest_framework import permissions
from django.core.exceptions import PermissionDenied


class CustomAccessPermission(permissions.BasePermission):
    message = "You cannot access objects created by other users."

    def has_object_permission(self, request, view, obj):
        if obj.user_id != request.user.id:
            raise PermissionDenied(self.message)
        return True

因此,在我的对象中,我存储了包含创建此对象的用户 ID 的user_id。我想检查请求中的id是否等于该user_id,如果用户可以看到此对象。因此,例如,当我运行 GET:http://localhost:8050/api/objects/4 时,我想获取 id=4 的对象user_id,如果它等于 request.user.id 那么我们将允许用户看到它,否则我们应该拒绝。与 DELETE 请求相同,应首先根据对象的user_id检查它们。

上面的这段代码不起作用,它无法访问我的权限类中的 has_object_permission() 方法。 我应该修改什么?

Django HTTP 端点

评论

0赞 willeM_ Van Onsem 11/16/2023
它不会,因为你自己实现,从而“侵蚀”了所有检查权限的逻辑。getdelete

答:

1赞 willeM_ Van Onsem 11/16/2023 #1

它不是因为你自己实现,并使用一个.就像 Django 的一样,an 只实现了处理 API 请求的视图的基础知识。它有一个可以检查对象权限的权限,但您需要自己执行此操作。getdeleteAPIViewViewAPIView.check_object_permissions(…)

这就是为什么人们几乎总是从提供更多功能开始的原因。事实上GenericAPIView

from rest_framework.views import GenericAPIView


class MyView(GenericAPIView):
    permission_classes = [CustomAccessPermission]
    queryset = MyObjectClass.objects.all()
    serializer_class = MySerializer
    lookup_url_kwarg = 'id'

    def get(self, request, id: int) -> Response:
        object = self.get_object()
        serializer = MySerializer(object)
        return Response(serializer.data)

    def delete(self, request, id: int):
        object = self.get_object()
        object.status = MyObjectClass.Status.DELETED
        object.save()
        return Response(status=status.HTTP_200_OK, data=id)

但是,我们仍然可以减少样板代码的数量,并让 Django REST 框架自己实现方法:

from rest_framework.generics import RetrieveDestroyAPIView


class MyView(RetrieveDestroyAPIView):
    permission_classes = [CustomAccessPermission]
    queryset = MyObjectClass.objects.all()
    serializer_class = MySerializer
    lookup_url_kwarg = 'id'

    def perform_destroy(self, instance):
        instance.status = MyObjectClass.Status.DELETED
        instance.save()

就是这样。如果在模型本身上实现“软删除”:即重写 MyObjectClass 本身的方法,则无需重写 。.delete()perform_destroy

评论

1赞 Mario Berg 11/16/2023
非常感谢您的示例和解释!它帮助我解决了这个问题!