这是我的视图类:
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() 方法。 我应该修改什么?
这不是因为您自己实现了
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
。