Django REST自定义权限报错:Update Task APIView对象无action属性
问题根因
- 报错
'Update Task APIView' object has no attribute 'action'的原因:action是DRF ViewSet类的专属属性,你使用的UpdateAPIView、DestroyAPIView属于通用类视图,没有该属性,导致自定义权限类运行时抛出异常,权限校验逻辑直接失效,所以没有正常拦截非所有者的修改、删除操作。 - 权限配置冗余:更新、删除视图的权限类同时配置了
IsAuthenticatedOrReadOnly,该权限会允许所有登录用户执行写操作,和自定义的所有者校验逻辑冲突。
修改步骤
1. 修复自定义权限类Permissions.py
把原来基于view.action的判断逻辑改为基于请求方法判断,适配通用类视图场景:
from rest_framework import permissions class IsOwner(permissions.BasePermission): def has_object_permission(self, request, view, obj): # GET、HEAD、OPTIONS这类只读请求直接放行,对应你原有的查询放行需求 if request.method in permissions.SAFE_METHODS: return True # 增删改操作需要任务所有者才能执行 return obj.user == request.user
2. 修正视图层权限配置和创建逻辑
修改Views.py中的视图配置,移除冗余权限、补充创建任务时的用户绑定逻辑:
class TaskViewSet(ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ queryset = Task.objects.all() serializer_class = TaskSerializer permission_classes = [permissions.IsAuthenticated, IsOwner,] def perform_create(self, serializer): serializer.save(user=self.request.user) class ListTaskAPIView(generics.ListAPIView): serializer_class = TaskSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] model= Task def get_queryset(self): """ Optionally restricts the returned purchases to a given user, by filtering against a `username` query parameter in the URL. """ query = self.request.GET.get('search') if query: object_list = self.model.objects.filter(Q(title__icontains=query) | Q(text__icontains=query)) else: object_list = self.model.objects.all() return object_list class CreateTaskAPIView(ListCreateAPIView): """This endpoint allows for creation of a todo""" queryset = Task.objects.all() serializer_class = TaskSerializer # 要求登录才能创建任务 permission_classes = [permissions.IsAuthenticated] # 新增:创建时自动绑定当前登录用户为任务所有者 def perform_create(self, serializer): serializer.save(user=self.request.user) class UpdateTaskAPIView(UpdateAPIView): """This endpoint allows for updating a specific todo by passing in the id of the todo to update""" serializer_class = TaskSerializer # 移除冗余的IsAuthenticatedOrReadOnly,保留登录+所有者校验 permission_classes = [permissions.IsAuthenticated, IsOwner,] queryset = Task.objects.all() class DeleteTaskAPIView(DestroyAPIView): """This endpoint allows for deletion of a specific Todo from the database""" serializer_class = TaskSerializer # 移除冗余的IsAuthenticatedOrReadOnly,保留登录+所有者校验 permission_classes = [permissions.IsAuthenticated, IsOwner] queryset = Task.objects.all()
可选优化
你当前同时定义了TaskViewSet和多个单独的通用视图,urls.py中实际使用的是单独视图的路由,TaskViewSet没有配置路由未生效。如果不需要多套接口,可以直接使用ViewSet+Router的方式简化代码,不需要单独写增删改查的视图类。
内容的提问来源于stack exchange,提问作者Montio5
相关产品推荐
相关产品推荐

