Django模型两次保存触发IntegrityError唯一约束失败的原因
为什么两次保存会触发唯一约束错误?
这个问题的核心是递归调用save方法导致的重复插入操作,具体流程拆解如下:
当你创建一个value_to_pay=0的新Bill实例并调用save()时,会触发连锁反应:
- 第一次调用
save():此时实例是全新的,id为None,status默认是UNPAID,满足if not self.status == PAID and self.value_to_pay <= 0的条件,于是调用set_status_to_paid()方法。 - 在
set_status_to_paid()中,你把status设为PAID,然后再次调用self.save()——这就触发了递归调用。 - 第二次进入
save()方法:此时status已经是PAID,不再满足if判断,直接执行super().save()。这一步会向数据库插入新记录,数据库自动生成id并赋值给实例。 - 递归调用完成后,回到第一次的
save()方法,继续执行super().save()。这时候实例已经有了id(来自递归中的插入操作),但Django在当前的save流程中,会尝试再次插入这条记录(因为最初的调用是针对新对象的插入),而数据库中已经存在这个id的记录,于是就触发了UNIQUE constraint failed: bill.id错误。
修复方案
你已经发现移除set_status_to_paid()里的save()调用就能解决问题,这是完全正确的做法。我们不需要在set_status_to_paid()里单独保存,只需要修改status的值,让第一次save()方法最后的super().save()一次性完成所有字段的保存即可。
修改后的代码示例:
def set_status_to_paid(self): self.status = PAID # 移除self.save()调用 def save(self, *args, **kwargs): if not self.status == PAID and self.value_to_pay <= 0: self.set_status_to_paid() super().save(*args, **kwargs)
这样整个流程只会执行一次super().save(),无论是新创建还是更新对象,都不会出现重复插入的问题。
内容的提问来源于stack exchange,提问作者Jad S
相关产品推荐
相关产品推荐

