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

如何为ListCreateAPIView的GET和POST方法设置不同权限?

问题

在使用ListCreateAPIView和ModelSerializer时,希望为GET方法设置IsAuthenticated权限,为POST方法设置IsTeamLeader权限,但不想通过单一权限类在has_permission中判断请求方法的方式实现,该怎么做?

原有代码如下:

@permission_classes([IsAuthenticated])
class ManagerListView(ListCreateAPIView):
    queryset = Manager.objects.all()
    serializer_class = ManagerSerializer


class IsTeamLeader(permissions.BasePermission):
    def has_permission(self, request, view):
        if Manager.objects.filter(pk=request.user.pk).exists():
            return Manager.objects.get(pk=request.user.pk).is_team_leader


class ManagerSerializer(serializers.ModelSerializer):
    password1 = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True)
    fields = serializers.JSONField(write_only=True)

    def validate(self, data):
        if data['password1'] != data['password2']:
            raise serializers.ValidationError('Passwords must match.')
        return data

    def create(self, validated_data):
        data = {
            key: value for key, value in validated_data.items()
            if key not in ('password1', 'password2')
        }
        data['password'] = validated_data['password1']
        user = self.Meta.model.objects.create_user(**data)
        return user

    class Meta:
        model = Manager
        fields = ('id', 'email', 'first_name', 'last_name', 'username', 'role', 'is_team_leader', 'password1', 'password2', 'fields')
        read_only_fields = ('id', 'first_name', 'last_name', 'role', 'is_team_leader', 'address', 'contact')
解决方案

直接在视图类中重写get_permissions()方法,根据当前请求的HTTP方法返回对应的权限类实例列表,就能实现不同方法绑定不同权限,无需在单一权限类中判断请求方法。

修改后的完整代码

from rest_framework import permissions, generics

class ManagerListView(generics.ListCreateAPIView):
    queryset = Manager.objects.all()
    serializer_class = ManagerSerializer

    def get_permissions(self):
        # 根据请求方法返回对应权限
        if self.request.method == 'GET':
            return [permissions.IsAuthenticated()]
        elif self.request.method == 'POST':
            return [IsTeamLeader()]
        # 其他方法默认返回空权限列表(可根据需求自行调整)
        return []


class IsTeamLeader(permissions.BasePermission):
    def has_permission(self, request, view):
        # 先校验用户是否已认证,避免未登录请求触发数据库查询报错
        if not request.user.is_authenticated:
            return False
        # 优化查询逻辑:假设Manager与User为一对一关联,直接通过关联字段获取
        try:
            manager = request.user.manager
            return manager.is_team_leader
        except Manager.DoesNotExist:
            return False


class ManagerSerializer(serializers.ModelSerializer):
    password1 = serializers.CharField(write_only=True)
    password2 = serializers.CharField(write_only=True)
    fields = serializers.JSONField(write_only=True)

    def validate(self, data):
        if data['password1'] != data['password2']:
            raise serializers.ValidationError('密码必须匹配。')
        return data

    def create(self, validated_data):
        data = {
            key: value for key, value in validated_data.items()
            if key not in ('password1', 'password2')
        }
        data['password'] = validated_data['password1']
        user = self.Meta.model.objects.create_user(**data)
        return user

    class Meta:
        model = Manager
        fields = ('id', 'email', 'first_name', 'last_name', 'username', 'role', 'is_team_leader', 'password1', 'password2', 'fields')
        read_only_fields = ('id', 'first_name', 'last_name', 'role', 'is_team_leader', 'address', 'contact')

关键说明

  1. 重写get_permissions方法:这是DRF视图类提供的钩子方法,支持动态返回权限实例。通过判断self.request.method,为GET和POST方法分别绑定对应的权限类。
  2. 优化IsTeamLeader权限类:新增用户认证前置检查,避免未登录请求触发数据库查询错误;同时通过用户关联字段获取Manager实例,减少一次数据库查询(若你的模型关联方式不同,可对应调整查询逻辑)。
  3. 移除全局权限装饰器:原有的@permission_classes([IsAuthenticated])装饰器不再需要,权限控制完全由get_permissions方法动态处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:10:44