Permission类has_object_permission方法未触发,评论删除权限失效
问题分析与解决方案
核心问题
你的自定义权限方法has_object_permission未执行,是因为重写的destroy方法完全跳过了DRF内置的权限校验流程。DRF的DestroyAPIView默认会通过get_object()获取目标对象,并自动触发check_object_permissions()来调用你的权限校验逻辑,但你直接在destroy里查询并删除评论,完全绕开了这个环节,导致权限检查从未触发。
解决方案
方案1:复用DRF内置校验流程(推荐)
修改视图,通过get_object()获取评论对象,让DRF自动触发权限检查:
class CommentPostApiView(generics.ListCreateAPIView, generics.DestroyAPIView): serializer_class = serializers.CommentPostSerializer authentication_classes = (TokenAuthentication,) permission_classes = [IsAuthenticated, IsCommentOwnerOrPostOwner] def get_queryset(self): post_id = self.kwargs.get('post_id') return models.CommentPost.objects.filter(post__pk=post_id, reply_to_comment__isnull=True) # 保留原create方法不变 @transaction.atomic def create(self, request, *args, **kwargs): # ... 原create代码 ... # 重写destroy方法,复用get_object触发权限校验 @transaction.atomic def destroy(self, request, *args, **kwargs): comment = self.get_object() post_id = comment.post.id comment.delete() models.PicPost.objects.filter(pk=post_id).update(comments_count=F('comments_count')-1) return Response({"detail": "Comment deleted successfully."}, status=status.HTTP_200_OK) # 重写get_object,获取要删除的评论并触发权限检查 def get_object(self): comment_id = self.kwargs.get('parent_comment_id') try: obj = models.CommentPost.objects.select_for_update().get(pk=comment_id) except models.CommentPost.DoesNotExist: raise ValidationError("This comment does not exist") self.check_object_permissions(self.request, obj) return obj
方案2:手动触发权限检查
如果不想修改get_object,也可以在自定义destroy方法里手动调用权限校验:
@transaction.atomic def destroy(self, request, *args, **kwargs): comment_id = self.kwargs.get('parent_comment_id') try: comment = models.CommentPost.objects.select_for_update().get(pk=comment_id) # 手动触发权限检查 self.check_object_permissions(request, comment) post_id = comment.post.id comment.delete() models.PicPost.objects.filter(pk=post_id).update(comments_count=F('comments_count')-1) except models.CommentPost.DoesNotExist: raise ValidationError("This comment does not exist") return Response({"detail": "Comment deleted successfully."}, status=status.HTTP_200_OK)
额外优化点
- 修正HTTP状态码:删除成功应返回
status.HTTP_200_OK或status.HTTP_204_NO_CONTENT,而非201_CREATED(201是创建成功的状态码)。 - 简化视图继承:
ListCreateAPIView已继承GenericAPIView,无需重复声明。
验证
修改后,当非评论所有者/非帖子所有者尝试删除评论时,DRF会自动返回403 Forbidden,同时你终端的调试print语句会输出内容,说明has_object_permission已正常执行。
内容的提问来源于stack exchange,提问作者Shantanu189
相关产品推荐
相关产品推荐

