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

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,提问作者Константин Манойло

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:32:57