Django DRF多对多关联场景下序列化器id字段丢失问题咨询
问题原因
- DRF的
ModelSerializer默认将模型主键id字段设置为只读字段,反序列化(将请求JSON转换为validated_data)时会自动过滤只读字段,所以你拿到的lines数据里没有id。 - 你使用的
PriceLineSerializerTest没有显式声明id字段为可写字段,因此默认遵循只读规则,反序列化时直接丢弃了传入的id值。
解决方案
第一步:修改嵌套的PriceLine序列化器
显式声明id字段允许读写:
class PriceLineSerializerTest(serializers.ModelSerializer): # 显式声明id字段,允许反序列化时接收传入值 id = serializers.IntegerField(required=False) class Meta: model = PriceLine fields = ['id', 'price', 'product']
第二步:补全PriceTableSerializer的update逻辑
class PriceTableSerializer(serializers.ModelSerializer): """ PriceTableSerializer """ lines = PriceLineSerializerTest(many=True) class Meta: model = PriceTable exclude = ['standard', 'client',] def update(self, instance, validated_data): instance.name = validated_data.get('name', instance.name) instance.save() lines_data = validated_data.get('lines', []) # 存储处理后的PriceLine实例,用于后续更新多对多关联 processed_lines = [] for line_data in lines_data: line_id = line_data.get('id') if line_id: # 已有id则更新对应PriceLine try: line = PriceLine.objects.get(id=line_id) line.price = line_data.get('price', line.price) line.product = line_data.get('product', line.product) line.save() processed_lines.append(line) except PriceLine.DoesNotExist: # 可根据业务需求决定抛出异常或者创建新条目 raise serializers.ValidationError(f"价目条目id={line_id}不存在") else: # 没有id则创建新的PriceLine new_line = PriceLine.objects.create(**line_data) processed_lines.append(new_line) # 更新多对多关联,替换原有关联关系 instance.lines.set(processed_lines) return instance
注意事项
- 如果业务不允许在更新价目表时新增PriceLine,可删除创建新条目的逻辑,对无id的传入数据直接抛校验错误
- PATCH请求如果未传入
lines字段,不会修改原有价目条目关联,符合局部更新的语义 - 可根据需求添加事务控制,避免更新一半失败导致数据不一致
内容的提问来源于stack exchange,提问作者darkvodka
相关产品推荐
相关产品推荐

