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方法时:
- 原来的代码会查询所有匹配
client和template的记录,没有排除当前要恢复的实例。 - 由于恢复操作通常在事务中进行,数据库可能会看到未提交的恢复记录,导致
count()>0的判断为真,触发ValidationError。
修改后的代码通过exclude(pk=self.pk)解决了这个问题:
- 对于新建记录:
self.pk为None,exclude不会生效,正常检查是否有冲突记录。 - 对于更新/恢复记录:排除当前实例,只检查数据库中已存在的其他冲突记录——你已经删除了唯一的冲突记录,所以不会触发校验错误。
另外,用exists()代替count()>0更高效,因为数据库只需判断是否存在匹配记录,不需要统计总数。
内容的提问来源于stack exchange,提问作者Basti G.
相关产品推荐
相关产品推荐

