python - Django/MySQL 唯一约束如何将 NULL 视为相等

标签 python mysql django model

我有一个 Django 模型,它有一个递归字段。简化版本如下。这个想法大致是在sql中有一个树形数据结构。显然,我遇到的问题是 Django does not treat NULLs as equal 。现在的问题是,由于每棵树的根都必然有一个“空指针”,我可以有两个相同的树,但 Django 会因为 NULL 值而将它们视为不同的。如何实现下面的 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')
                ]

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

最佳答案

您可以使用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)

关于python - Django/MySQL 唯一约束如何将 NULL 视为相等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59514031/

相关文章:

python - 在 PyCharm 上添加 'import lettuce' 时出错

python - python脚本的CPU使用率

Python MySQLClient 安装失败,出现 "metadata-generation-failed"

django图片上传无法导入名称_imaging

python - 为什么重写 save() 方法会被绕过?

python - 获取测试套件中每个测试的 SQL 查询计数概览

python - 在另一个 csv 文件中查找一个 csv 文件的值并打印该行

python - GLib-GIO-Message : Using the 'memory' GSettings backend. 您的设置将不会被保存或与其他应用程序共享

php - 使用别名从 View 更新 MySQL 表

sql - 修复 mysql 查询以返回子组内的随机行