Django Rest Framework嵌套对象反序列化外键province更新异常求助
问题根因
DRF嵌套序列化器的默认写入逻辑是尝试创建或更新嵌套对应的模型实例,你当前的场景仅需要关联已存在的ValidProvince实例,不需要修改省份表数据,因此默认逻辑不符合需求:
- 加
read_only=True时,province字段不会参与写入逻辑,所以更新不生效 - 去掉
read_only=True时,序列化器尝试创建新的ValidProvince实例,和数据库中已存在的主键冲突,因此抛出记录已存在的错误
你需要自定义序列化器的update和create方法来处理外键关联逻辑,不需要修改现有请求传参结构,适配方案如下:
具体实现
修改AgentBusinessAddressSerializer代码即可:
class AgentBusinessAddressSerializer(serializers.HyperlinkedModelSerializer): province = ValidProvinceSerializer() # 移除read_only参数 class Meta: model = AgentBusinessAddress fields = ('agent_id', 'operator_id', 'dlc', 'address', 'city', 'province', 'postal_code', 'valid_address') def update(self, instance, validated_data): # 提取嵌套的省份数据 province_data = validated_data.pop('province', None) if province_data: # 取省份编码作为主键查询已存在的省份实例 province_code = province_data.get('province') try: province_instance = ValidProvince.objects.get(province=province_code) instance.province = province_instance except ValidProvince.DoesNotExist: raise serializers.ValidationError({"province": "无效的省份编码"}) # 其余字段走默认更新逻辑 return super().update(instance, validated_data) # 如果需要支持POST创建地址,同步重写create方法 def create(self, validated_data): province_data = validated_data.pop('province', None) if not province_data: raise serializers.ValidationError({"province": "省份为必填项"}) province_code = province_data.get('province') try: province_instance = ValidProvince.objects.get(province=province_code) validated_data['province'] = province_instance except ValidProvince.DoesNotExist: raise serializers.ValidationError({"province": "无效的省份编码"}) return super().create(validated_data)
效果说明
修改后你的原请求payload不需要做任何调整,后端会自动提取嵌套对象中的省份编码,查询匹配的已有省份实例关联到地址对象,最终执行的SQL和你预期的完全一致,不会修改valid_province表的任何数据。
内容的提问来源于stack exchange,提问作者lycosis
相关产品推荐
相关产品推荐

