Django Rest Framework中含非空read_only字段的数据创建问题解决
解决方案:DRF实现创建必填、更新只读的字段
针对你遇到的问题——需要account_name字段在创建时可传入且必填,在更新时禁止修改,这里提供三种实用方案:
方案1:拆分序列化器(最清晰直观)
创建两个序列化器,分别对应创建和更新/查询场景,在视图中根据动作切换:
# 创建专用序列化器(无read_only限制) class AccountCreateSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] # 更新/查询专用序列化器(设置account_name为只读) class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] read_only_fields = ['account_name'] # 在视图集中切换序列化器 class AccountViewSet(viewsets.ModelViewSet): queryset = Account.objects.all() def get_serializer_class(self): # 创建动作用创建序列化器,其他用默认 if self.action == 'create': return AccountCreateSerializer return AccountSerializer
方案2:重写update方法(单序列化器解决)
保留单个序列化器,移除read_only_fields配置,重写update方法剔除account_name的更新请求:
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] def update(self, instance, validated_data): # 弹出account_name字段,禁止更新 validated_data.pop('account_name', None) # 调用父类方法完成其他字段更新 return super().update(instance, validated_data)
创建时正常传入account_name即可满足模型非空约束,更新时即使传入该字段也会被忽略,不会修改原数据。
方案3:字段校验拦截(更严格的校验)
单独声明字段,通过校验方法限制更新时的修改操作:
class AccountSerializer(serializers.ModelSerializer): # 明确声明字段,创建时必填 account_name = serializers.CharField(required=True) class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] def validate_account_name(self, value): # 仅在更新时校验:如果传入的value和原实例不一致,抛出错误 if self.instance and self.instance.account_name != value: raise serializers.ValidationError("account_name字段不允许修改") return value
这种方案会在更新时直接报错提示,比方案2更直观,能明确告知用户该字段不可修改。
内容的提问来源于stack exchange,提问作者Sinister _
相关产品推荐
相关产品推荐

