DRF marketplace接口中如何实现不同角色对ProjectOffer字段的修改权限控制?
针对你在DRF搭建marketplace API时遇到的ProjectOffer字段权限控制问题,我整理了两种基于ModelViewSet的可行方案,你可以根据项目的实际情况选择:
方案一:拆分序列化器(按角色动态分配)
这个方案的核心是给品牌和创作者分别定义专属的序列化器,通过视图动态判断用户角色返回对应序列化器,直观控制可编辑字段。
1. 定义角色专属序列化器
from rest_framework import serializers from .models import ProjectOffer class BrandProjectOfferSerializer(serializers.ModelSerializer): class Meta: model = ProjectOffer fields = ['id', 'title', 'description', 'author', 'project', 'created_on', 'updated_on', 'status'] # 品牌仅能编辑title、description,其余字段设为只读 read_only_fields = ['id', 'author', 'project', 'created_on', 'updated_on', 'status'] class CreatorProjectOfferSerializer(serializers.ModelSerializer): class Meta: model = ProjectOffer fields = ['id', 'title', 'description', 'author', 'project', 'created_on', 'updated_on', 'status'] # 创作者仅能编辑status,其余字段设为只读 read_only_fields = ['id', 'title', 'description', 'author', 'project', 'created_on', 'updated_on']
2. 编写权限类,确保用户只能操作自己有权限的Offer
from rest_framework.permissions import BasePermission from .models import Brand, Creator class IsBrandOwnerOrCreatorOfProject(BasePermission): def has_object_permission(self, request, view, obj): # 品牌用户:只能修改自己发起的Offer if request.user.is_brand: brand = Brand.objects.get(user=request.user) return obj.author == brand # 创作者用户:只能修改自己项目收到的Offer elif request.user.is_creator: creator = Creator.objects.get(user=request.user) return obj.project.author == creator # 超级管理员拥有全部权限(可根据需求调整) return request.user.is_superuser
3. 配置ModelViewSet
from rest_framework import viewsets from .models import ProjectOffer from .serializers import BrandProjectOfferSerializer, CreatorProjectOfferSerializer from .permissions import IsBrandOwnerOrCreatorOfProject class ProjectOfferViewSet(viewsets.ModelViewSet): queryset = ProjectOffer.objects.all() permission_classes = [IsBrandOwnerOrCreatorOfProject] def get_serializer_class(self): # 根据当前登录用户的角色动态返回序列化器 if self.request.user.is_brand: return BrandProjectOfferSerializer elif self.request.user.is_creator: return CreatorProjectOfferSerializer # 管理员默认使用全字段序列化器(可自定义) return super().get_serializer_class() def perform_create(self, serializer): # 创建Offer时自动填充品牌作者,避免前端传入 if self.request.user.is_brand: brand = Brand.objects.get(user=self.request.user) serializer.save(author=brand)
方案二:权限类+视图字段过滤
这个方案用统一的序列化器,把字段权限逻辑集中在自定义权限类里,通过检查请求中的字段来限制修改范围。
1. 基础序列化器
from rest_framework import serializers from .models import ProjectOffer class ProjectOfferSerializer(serializers.ModelSerializer): class Meta: model = ProjectOffer fields = ['id', 'title', 'description', 'author', 'project', 'created_on', 'updated_on', 'status'] # 基础只读字段,所有角色都不能修改 read_only_fields = ['id', 'author', 'project', 'created_on', 'updated_on']
2. 带字段权限检查的自定义权限类
from rest_framework.permissions import BasePermission from .models import Brand, Creator class CanModifyOnlyAllowedFields(BasePermission): def has_object_permission(self, request, view, obj): # 非更新请求(GET/POST)先验证基础权限 if request.method not in ['PUT', 'PATCH']: if request.user.is_brand: brand = Brand.objects.get(user=request.user) return obj.author == brand elif request.user.is_creator: creator = Creator.objects.get(user=request.user) return obj.project.author == creator return request.user.is_superuser # 更新请求时,检查字段权限 if request.user.is_brand: # 品牌仅允许修改title、description allowed_fields = {'title', 'description'} # 遍历请求字段,确保没有越权修改 for field in request.data: if field not in allowed_fields: return False # 同时验证是自己发起的Offer brand = Brand.objects.get(user=request.user) return obj.author == brand elif request.user.is_creator: # 创作者仅允许修改status allowed_fields = {'status'} for field in request.data: if field not in allowed_fields: return False # 验证是自己项目的Offer creator = Creator.objects.get(user=request.user) return obj.project.author == creator # 超级管理员不受限制 return request.user.is_superuser
3. 配置ModelViewSet
from rest_framework import viewsets from .models import ProjectOffer from .serializers import ProjectOfferSerializer from .permissions import CanModifyOnlyAllowedFields class ProjectOfferViewSet(viewsets.ModelViewSet): queryset = ProjectOffer.objects.all() serializer_class = ProjectOfferSerializer permission_classes = [CanModifyOnlyAllowedFields] def perform_create(self, serializer): # 自动填充品牌作者 if self.request.user.is_brand: brand = Brand.objects.get(user=self.request.user) serializer.save(author=brand)
方案对比
- 方案一优点:逻辑清晰,每个角色的字段权限直观体现在序列化器中,容易维护;缺点:如果后续角色或字段规则变化,需要修改序列化器和视图的判断逻辑。
- 方案二优点:序列化器统一,字段权限集中在权限类管理,适合规则复杂的场景;缺点:权限类的逻辑相对复杂,需要仔细处理PATCH请求的字段检查。
额外注意事项
- 确保用户的
is_creator和is_brand字段在创建用户时正确设置,避免权限判断出错。 - 如果需要支持部分更新(PATCH),方案二的权限类已经做了字段检查,方案一的序列化器也会自动忽略只读字段的修改请求。
内容的提问来源于stack exchange,提问作者Константин Манойло
相关产品推荐
相关产品推荐

