DRF反序列化数据时如何获取已存在模型实例而非新建实例
解决方法
问题原因
默认仅传入data参数初始化序列化器时,DRF会按照新建实例的逻辑做校验,你的Clinic模型中name和label字段设置了唯一约束,对应实例已存在就会触发校验报错。
方案1:使用instance参数走更新校验逻辑(推荐)
如果你的序列化数据中包含主键clinicid,可以先通过主键查询到实例再传入序列化器,此时会走更新逻辑,不会触发新建场景的唯一校验,仅需提取主键一个字段即可,不需要处理其他参数:
clinic_data = biovardata['linkedclinic'] # 仅需提取主键查询实例 clinic_instance = Clinic.objects.get(clinicid=clinic_data['clinicid']) # 传入instance参数,partial=True表示允许部分字段更新 clinicserializer = ClinicSerializer(instance=clinic_instance, data=clinic_data, partial=True) if clinicserializer.is_valid(): # serializer.instance就是你需要的原有模型实例 cl = clinicserializer.instance
方案2:自定义序列化器实现全自动查询(完全不需要手动提取字段)
如果不想提取任何字段,可以直接修改序列化器,关闭新建场景的唯一校验,新增封装好的查询方法:
class ClinicSerializer(serializers.ModelSerializer): class Meta: model = Clinic fields = [ 'clinicid', 'name', 'label', 'email', 'mobile', 'alternate', 'address', 'locationlink', 'googlepaynumber', 'upi_id', 'reviewlink', 'locationlink', 'bookinglink' ] # 仅移除name和label的唯一校验,其他格式、必填校验保留 extra_kwargs = { 'name': {'validators': []}, 'label': {'validators': []}, } def get_existing_instance(self): # 校验通过后直接用所有校验后的数据查询实例 return Clinic.objects.get(**self.validated_data)
调用逻辑完全不需要处理字段提取:
clinic_data = biovardata['linkedclinic'] clinicserializer = ClinicSerializer(data=clinic_data) if clinicserializer.is_valid(): cl = clinicserializer.get_existing_instance()
补充说明
- 若查询可能匹配不到实例,可以自行在查询逻辑中捕获
Clinic.DoesNotExist异常做兼容处理。 - 如果你的业务场景需要用非主键的多个字段匹配查询,方案2更适配,不需要手动拼接查询参数。
内容的提问来源于stack exchange,提问作者Joel G Mathew
相关产品推荐
相关产品推荐

