Django:对于唯一性约束,如何将null视为等于一切



在标题中,我的意思是等于任何值,而不仅仅是其他null。

举个例子,我们有一个家庭,有家庭成员(人(和电子设备。有些电子设备是个人的,属于一个人,但有些不属于任何一个家庭成员,比如研究中的普通电脑。然后,我们可以对这样的电子设备进行建模:

class ElectronicDevice(models.Model):
name = models.CharField(null=False, max_length=64)
owner = models.ForeignKey(HouseMember, null=True, on_delete=models.CASCADE)

现在让我们假设,从众议院成员的角度来看,我们希望设备名称是唯一的。家庭成员不应拥有两个名称相同的设备。因此,名称和所有者应该是唯一的,但也不应该有两个设备,一个专用设备和一个公用设备(所有者为null(具有相同的名称。

因此,一个正常的UniqueConstraint:

class Meta:
constraints = [
models.UniqueConstraint(fields=['name', 'owner'], name='uniqe_device_name'),
]

不会这样做,因为如果其中一个设备的所有者为null,它仍然允许两个设备具有相同的名称。仅约束名称字段:

class Meta:
constraints = [
models.UniqueConstraint(fields=['name', ], name='uniqe_device_name'),
]

也不会这样做,因为这不允许两个家庭成员对他们的私人设备进行相同的命名,尽管我们确实希望允许这样做。

我目前的尝试是限制名称和所有者的唯一性,然后使用CheckConstraint,如果已经有一个通用设备(所有者为空(使用该名称,则不允许使用该名称:

class Meta:
constraints = [
models.UniqueConstraint(fields=['name', 'owner'], name='uniqe_device_name'),
models.CheckConstraint(check=???, name='no_common_device_with_same_name')
]

这是最好的方法还是有更好的解决方案?如果这是最好的解决方案:如何为此编写CheckConstraint

也许你可以这样尝试:

constraints = [ 
models.UniqueConstraint(fields=['name', 'owner'], condition = Q(owner__isnull=False), name='uniqe_device_name'),
models.UniqueConstraint(fields=['name'], condition = Q(owner__isnull=True), name='uniqe_device_name_without_owner')
]

更多信息可在文档中找到。

更新

如果需要无法从"约束"处理的自定义条件,则最好重写保存方法。例如:

class ElectronicDevice(models.Model):
...
def save(self, *args, **kwargs):
if some conditions:
raise ValidationError()
super().save(*args, **kwargs)

相关内容

最新更新