如何测试 Model.clean() 函数的唯一性?

How to test uniqueness in a Model.clean() function?

我有一个模型 UniqueConstraint:

class MyModel(models.Model)
    name = models.CharField()
    title = models.CharField()
  
    class Meta:
        constraints = [ models.UniqueConstraint(
                          fields=['name', 'title'],
                          name="unique_name_and_title") ]

这很好用,并在创建 2 个具有相同值的对象时引发 IntegrityError

问题是 UniqueConstraint 没有向用户呈现漂亮的 ValidationError。通常,我会在 Model.clean() class 中添加这些,但是如果我这样做,那么它将在 Update 上失败,因为正在更新的实例已经存在:

def clean(self):
    if MyModel.objects.filter(title=self.title, name=self.name):
             raise ValidationError({'title':'An object with this name+title already exists'})

I 如何创建一个 ValidationError 如果它是 UPDATE 而不是 INSERT 则通过?

我知道我可以在 ModelForm 上执行此操作并使用 self.instance 检查实例是否已经存在,但我想将其应用于模型 class 而没有依赖于 ModelForm。

您可以从您检查的查询集中排除对象:

def clean(self):
    qs = MyModel.objects.<b>exclude(pk=self.pk)</b>.filter(title=self.title, name=self.name)
    if qs.<b>exists()</b>:
        raise ValidationError({'title':'An object with this name+title already exists'})
    return super().clean()

如果对象尚未保存,它将检查 .exclude(pk=None),但这不会排除任何对象,因为主键不可为空。

这里使用.exists() [Django-doc]效率更高,因为它限制了从数据库到Django/Python层的带宽。