如何为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')
关键说明
- 重写
get_permissions方法:这是DRF视图类提供的钩子方法,支持动态返回权限实例。通过判断self.request.method,为GET和POST方法分别绑定对应的权限类。 - 优化
IsTeamLeader权限类:新增用户认证前置检查,避免未登录请求触发数据库查询错误;同时通过用户关联字段获取Manager实例,减少一次数据库查询(若你的模型关联方式不同,可对应调整查询逻辑)。 - 移除全局权限装饰器:原有的
@permission_classes([IsAuthenticated])装饰器不再需要,权限控制完全由get_permissions方法动态处理。
内容的提问来源于stack exchange,提问作者Florent
相关产品推荐
相关产品推荐

