【问题标题】:Django/MySQL Unique Constraint how to treat NULLs as equalDjango / MySQL唯一约束如何将NULL视为平等
【发布时间】:2020-04-18 04:59:26
【问题描述】:

我有一个具有递归字段的 Django 模型。简化版本如下。这个想法大致是在sql中有一个树形数据结构。我遇到的问题显然是Django does not treat NULLs as equal。现在的问题是,由于每棵树的根都必须有一个“空指针”,我可以有两棵相同的树,但由于 NULL 值,Django 会将它们视为不同的。如何实现下面的 UniqueConstraint,以便具有 NULL 链接值和相等节点值的两个“链接”对象将被视为相同,并且无法通过 UniqueConstraint 测试?谢谢。

class Link(models.Model):
    node = models.ForeignKey(Node, on_delete=models.CASCADE) 

    link = models.ForeignKey('self', on_delete = models.CASCADE, null=True)


    class Meta:

        constraints = [
                models.UniqueConstraint(['node', 'link'], name='pipe_unique')
                ]

编辑 当然,理想情况下,约束将由 db 强制执行。但即使我可以通过在某处挂钩或使用自定义约束在应用程序逻辑中强制执行它,那也足够了。

【问题讨论】:

  • 这是一个 MySQL 问题。 MySQL 在唯一约束中不将 NULL 列视为相等
  • @IainShelvington 查看更新

标签: python mysql django model


【解决方案1】:

您可以通过custom constraint 来做到这一点

UniqueConstraint(fields=['node'], condition=Q(link__isnull=True), name='unique_root_node')

编辑:

如果您希望手动添加检查,您可以在 Linksave 方法和 clean 方法中执行此操作,以便在您保存实例之前它可以在任何模型表单中运行

def clean(self):
    if self.node_id and not self.link_id:
        if self.__class__.objects.exclude(pk=self.pk).filter(node=self.node, link__isnull=True).exists():
            raise ValidationError(f'A root node already exists for {self.node}')

排除pk=self.pk可避免在更新对象时与自身发生冲突

def save(self, *args, **kwargs):
    self.clean()
    super().save(*args, **kwargs)

【讨论】:

  • 这不起作用。我正在浏览 Django 代码库,试图找出原因。
猜你喜欢
  • 2021-06-20
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 2018-11-29
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
相关资源
最近更新 更多