Django保存Recovery模型时触发UNIQUE约束失败错误但数据仍被保存
问题原因与解决方案
核心问题原因
- 你自定义的
Recovery模型save方法重复调用父类save,且调用时携带了序列化器传入的force_insert=True参数:- 新建对象时第一次调用
super().save(*args, **kwargs):因为携带force_insert=True,会执行INSERT操作,数据库生成自增主键,self.id被赋值,数据已经写入数据库 - 方法末尾无判断再次调用
super().save(*args, **kwargs):依然携带force_insert=True参数,Django会忽略已有ID强制执行INSERT操作,用已存在的ID写入就触发主键UNIQUE约束报错
- 新建对象时第一次调用
- 第一次写入已经生效且没有事务回滚,所以出现「报错但数据保存成功」的矛盾现象
修复方案
修改Recovery模型的save方法,全程仅调用一次父类save即可,调整后的代码如下:
def save(self, *args, **kwargs): # 先处理所有业务逻辑 if self.party_order: # 注意你这里的字段名疑似拼写错误:pandding_amount → pending_amount order = PartyOrder.objects.get(id=self.party_order.id) order.pandding_amount -= self.amount order.save() else: if self.status == 'Approved': if self.party_order: pl = PartyLedger(party=self.party,sales_officer=self.sale_officer, freight = self.party_order.freight,transaction_type='Credit', description=self.description, total_amount=self.amount) pl.save() else: pl = PartyLedger(party=self.party,sales_officer=self.sale_officer, transaction_type='Credit', description=self.description, total_amount=self.amount) pl.save() self.pl = pl if self.payment_method == 'Bank': bl = BankLedger(bank=self.bank,transaction_type='Debit', description=self.description, total_amount=self.amount) bl.save() self.bl = bl elif self.payment_method == 'Cash': cl = CashLedger(transaction_type='Debit', description=self.description, total_amount=self.amount) cl.save() self.cl = cl elif self.payment_method == 'Clearing': ccl = ClearingLedger(transaction_type='Debit', description=self.description, total_amount=self.amount) ccl.save() self.cll = ccl # 所有逻辑处理完成后仅调用一次父类save super(Recovery, self).save(*args, **kwargs)
其他需要修正的小问题
- 模型的
_str_方法格式错误,应该是双下划线:def __str__(self): - 视图中注释掉的异常捕获逻辑如果需要使用请打开,否则报错时会直接返回500错误,无法返回你定义的标准化响应
PartyOrder模型的pandding_amount字段疑似拼写错误,建议修正为pending_amount
内容的提问来源于stack exchange,提问作者Talha Mahmood
相关产品推荐
相关产品推荐

