Django:唯一字段重复值处理——Protein对象复用异常排查
问题分析
你的问题出在两个核心点:
ModelSerializer的默认验证拦截
Django REST Framework的ModelSerializer会自动继承模型字段的约束验证,包括unique=True规则。在你自定义的create方法执行之前,Serializer的验证阶段就会检查protein_id是否已存在,一旦发现重复就直接抛出「protein with this protein id already exists.」的验证异常,根本不会进入你写的try-except或get_or_create逻辑。create方法的逻辑错误
你在create里写了protein_data = validated_data.pop('protein'),但根据你描述的传入数据{'protein_id':ABC123},validated_data里并没有嵌套的protein键,这行代码会直接抛出KeyError,只是可能被前面的验证异常掩盖了。
解决方案
下面是修正后的代码,解决上述两个问题:
修正后的Serializer.py
from rest_framework import serializers from .models import Protein class ProteinSerializer(serializers.ModelSerializer): # 禁用默认的UniqueValidator,避免验证阶段抛出异常 protein_id = serializers.CharField( max_length=256, validators=[], required=True ) class Meta: model = Protein fields = ['protein_id', "sequence"] def create(self, validated_data): # 使用get_or_create复用已存在的对象,不存在则创建(原子操作,并发安全) protein, _ = Protein.objects.get_or_create( protein_id=validated_data['protein_id'], # defaults参数仅在创建新对象时生效,不会覆盖已存在对象的sequence defaults={'sequence': validated_data.get('sequence', '')} ) return protein
关键说明
- 禁用默认验证:通过显式定义
protein_id字段并设置validators=[],跳过DRF自动添加的UniqueValidator,让我们能在create方法里自己处理复用逻辑。 - 原子操作
get_or_create:这是Django ORM提供的安全操作,能避免并发场景下重复创建对象的问题,比手动try-except更可靠。 - 修正数据结构:直接使用
validated_data里的平级字段,不再错误地pop('protein'),匹配你传入的数据格式。
额外可选需求
如果希望复用已存在对象时,更新它的sequence字段,可以修改create方法:
def create(self, validated_data): protein, created = Protein.objects.get_or_create( protein_id=validated_data['protein_id'], defaults={'sequence': validated_data.get('sequence', '')} ) # 若对象已存在,更新sequence(按需选择) if not created and 'sequence' in validated_data: protein.sequence = validated_data['sequence'] protein.save() return protein
内容的提问来源于stack exchange,提问作者out1997
相关产品推荐
相关产品推荐

