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

DRF Serializer使用update_or_create报Unique Constraint Failed错误

问题根因

  • DRF 序列化器执行操作时,新增请求会调用create()方法,更新请求会调用update()方法,你仅重写了create()方法,PUT 更新请求走的默认update()逻辑,完全没有处理part字段的类型转换:你在序列化器中定义part为CharField接收字符串参数,但模型中part是OneToOneField关联Part表,默认update()方法会直接把字符串写入外键字段,要么触发外键约束错误,要么写入的part值已经存在关联的DocumentRef记录,触发唯一约束错误。
  • 你之前的update_or_create写法参数错误:没有显式指定查询条件,所有传入字段都会作为查询条件,只要修改了任意文件字段,就会触发新建逻辑,而part是唯一索引,新建必然报错。
  • get_object方法返回值类型不统一,查询不到记录时返回HttpResponse而非异常,后续逻辑传入序列化器会触发额外错误。

修复方案

1. 修正序列化器逻辑,统一处理字段转换、新增/更新逻辑

class PartSerializer(serializers.ModelSerializer):
    part = serializers.CharField()
    class Meta:
        model = DocumentRef
        fields = ('part', 'field1', 'field2', 'field3')

    # 统一处理入参字段转换,新增、更新请求都会先执行该逻辑
    def to_internal_value(self, data):
        internal_data = super().to_internal_value(data)
        # 把传入的part号字符串转换为Part实例
        try:
            part_inst = Part.objects.get(part_number=internal_data['part'])
            internal_data['part'] = part_inst
        except Part.DoesNotExist:
            raise serializers.ValidationError({"part": "指定的Part记录不存在"})
        return internal_data

    def create(self, validated_data):
        # 显式指定查询条件为part,其余字段作为更新值,避免误新建
        doc_ref, _ = DocumentRef.objects.update_or_create(
            part=validated_data['part'],
            defaults=validated_data
        )
        return doc_ref

    def update(self, instance, validated_data):
        # 更新前校验part唯一性:如果改了part值,要确认新值没有被其他记录占用
        new_part = validated_data['part']
        if new_part != instance.part and DocumentRef.objects.filter(part=new_part).exists():
            raise serializers.ValidationError({"part": "该Part已关联其他DocumentRef记录"})
        # 逐个更新字段
        instance.part = new_part
        instance.field1 = validated_data.get('field1', instance.field1)
        instance.field2 = validated_data.get('field2', instance.field2)
        instance.field3 = validated_data.get('field3', instance.field3)
        instance.save()
        return instance

2. 修正视图的查询逻辑

from rest_framework.exceptions import NotFound

class APIDetailTest(APIView):
    def get_object(self, pk):
        try:
            return DocumentRef.objects.get(pk=pk)
        except DocumentRef.DoesNotExist:
            # 抛出DRF标准异常,框架会自动返回404响应
            raise NotFound("对应DocumentRef记录不存在")
    
    # get、put方法保持原有逻辑即可

内容的提问来源于stack exchange,提问作者Josh_At_Sorenson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 12:45:05