You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST Framework打印has_object_permission实例及对象权限实现问题

Django REST Framework 权限问题解答

首先先说明你现有代码中两个直接导致权限失效的问题:

  1. ObjectOwnerPermission的has_object_permission方法逻辑错误:只要用户登录就直接返回True,后续判断对象所有者的代码永远不会执行
  2. 视图中的权限类属性名写错:正确属性名是permission_classes,你写的permissions_classes多了一个s,导致权限类没有被加载生效

1. 打印has_object_permission排查逻辑的方法

完全可以,你直接在该方法内加入打印语句或者日志输出即可,示例如下:

import logging
logger = logging.getLogger(__name__)

class ObjectOwnerPermission(BasePermission):
    message = "仅对象所有者可操作该资源"
    def has_object_permission(self, request, view, obj):
        # 打印/输出排查信息
        logger.info(f"请求用户: {request.user}, 对象作者: {obj.author}, 请求方法: {request.method}")
        # 修正后的逻辑:先判断登录,再判断是不是所有者
        if not request.user.is_authenticated:
            return False
        return obj.author == request.user

启动服务后发起请求,就能在控制台/日志文件中看到对应的参数输出,确认逻辑执行情况。


2. 除权限类外的其他实现方式

有三种常用的实现方案:

  • 重写视图的操作方法:直接在update、destroy方法内做校验,不符合条件直接抛出403异常
    示例:
    from rest_framework.exceptions import PermissionDenied
    
    class RetrieveUpdateProjectAPIView(generics.RetrieveUpdateAPIView):
        queryset = Project.objects.all()
        serializer_class = serializers.ProjectSerializer
    
        def update(self, request, *args, **kwargs):
            instance = self.get_object()
            if instance.author != request.user:
                raise PermissionDenied("仅所有者可修改项目")
            return super().update(request, *args, **kwargs)
    
  • 重写视图的get_object方法:统一处理当前视图所有对象操作的权限校验
    示例:
    def get_object(self):
        obj = super().get_object()
        if obj.author != self.request.user:
            raise PermissionDenied("仅所有者可操作该项目")
        return obj
    
  • 过滤查询集:直接排除非当前用户创建的对象,用户请求其他用户的对象会直接返回404
    示例:
    def get_queryset(self):
        return Project.objects.filter(author=self.request.user)
    

3. 基于Serializer校验的实现方法

可以实现,需要利用Serializer的context获取请求对象,在update方法或者validate方法内做校验,示例如下:

from rest_framework import serializers
from rest_framework.exceptions import PermissionDenied

class ProjectSerializer(serializers.ModelSerializer):
    # 其他字段定义省略
    class Meta:
        model = Project
        fields = "__all__"

    def update(self, instance, validated_data):
        # 从context中获取请求用户
        request = self.context.get("request")
        if request and instance.author != request.user:
            raise PermissionDenied("仅所有者可修改项目")
        return super().update(instance, validated_data)

注意:该方案仅能校验走Serializer更新的请求,删除操作不会经过Serializer的update方法,所以删除场景需要额外处理,建议搭配重写destroy方法使用。


修正后的原始代码参考

class ObjectOwnerPermission(BasePermission):
    message = "仅对象所有者可操作该资源"
    def has_object_permission(self, request, view, obj):
        if not request.user.is_authenticated:
            return False
        # 只读请求可以放开权限,需要全权限控制删掉下面这行即可
        if request.method in SAFE_METHODS:
            return True
        return obj.author == request.user


class RetrieveUpdateProjectAPIView(generics.RetrieveUpdateAPIView):
    # 修正属性名,去掉多余的s
    permission_classes = [ObjectOwnerPermission]
    queryset = Project.objects.all()
    serializer_class = serializers.ProjectSerializer

class DeleteProjectAPIView(generics.DestroyAPIView):
    permission_classes = [ObjectOwnerPermission]
    queryset = Project.objects.all()
    serializer_class = serializers.ProjectSerializer

内容的提问来源于stack exchange,提问作者Ahmed Yasin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 20:39:00