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

Django保存Recovery模型时触发UNIQUE约束失败错误但数据仍被保存

问题原因与解决方案

核心问题原因

  • 你自定义的Recovery模型save方法重复调用父类save,且调用时携带了序列化器传入的force_insert=True参数:
    1. 新建对象时第一次调用super().save(*args, **kwargs):因为携带force_insert=True,会执行INSERT操作,数据库生成自增主键,self.id被赋值,数据已经写入数据库
    2. 方法末尾无判断再次调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:45:04