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

Django-reversion与模型clean方法冲突问题咨询

问题原因与解决方案

这个问题的核心是你的clean方法没有排除当前正在操作的实例,导致恢复删除记录时触发了不必要的校验。

修复后的模型代码

修改Document模型的clean方法,加入排除当前实例的逻辑:

class Document(models.Model):
    name = models.CharField(max_length=255, blank=True, null=True)
    client = models.ForeignKey(Client, on_delete=models.CASCADE)
    template = models.ForeignKey(Template, on_delete=models.CASCADE)
    
    def clean(self):
        super().clean()
        if self.template.only_one:
            # 筛选相同client和template的记录
            matching_docs = Document.objects.filter(
                client=self.client,
                template=self.template
            )
            # 如果当前实例有主键(恢复/更新场景),排除自身
            if self.pk is not None:
                matching_docs = matching_docs.exclude(pk=self.pk)
            # 检查是否存在冲突记录
            if matching_docs.exists():
                raise ValidationError('Test')

为什么原来的代码会出问题?

当你恢复已删除的Document记录时,django-reversion会保留原实例的主键(self.pk)。在执行clean方法时:

  1. 原来的代码会查询所有匹配client和template的记录,没有排除当前要恢复的实例。
  2. 由于恢复操作通常在事务中进行,数据库可能会看到未提交的恢复记录,导致count()>0的判断为真,触发ValidationError。

修改后的代码通过exclude(pk=self.pk)解决了这个问题:

  • 对于新建记录:self.pk为None,exclude不会生效,正常检查是否有冲突记录。
  • 对于更新/恢复记录:排除当前实例,只检查数据库中已存在的其他冲突记录——你已经删除了唯一的冲突记录,所以不会触发校验错误。

另外,用exists()代替count()>0更高效,因为数据库只需判断是否存在匹配记录,不需要统计总数。

内容的提问来源于stack exchange,提问作者Basti G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:26