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

问题描述 投票:0回答:1

这是我的视图类:

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

因此,在我的对象中,我存储了 user_id,其中包含创建该对象的用户的 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 endpoint
1个回答
0
投票

这不是因为您自己实现了

get
delete
,并使用了
APIView
。就像 Django 的
View
一样,
APIView
只实现处理 API 请求的视图的基础知识。它有一个
.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()

就是这样。如果您在模型本身上实现“软删除”:即覆盖

.delete()
 本身的 
MyObjectClass
方法,则不需要覆盖
perform_destroy

© www.soinside.com 2019 - 2024. All rights reserved.