如何在PostgreSQL中强制NULL值的唯一性

jgwigjjp  于 2023-03-17  发布在  PostgreSQL
关注(0)|答案(3)|浏览(223)

我有一个模型,其中有一个不可为空的CharField和两个可为空的CharField

class MyModel(models.Model):
    name = models.CharField('Name', max_length=255, null=False)
    title = models.CharField('Title', max_length=255, blank=True)
    position = models.CharField('Position', max_length=255, blank=True)

我想确保nametitleposition在一起是唯一的,因此使用UniqueConstraint

def Meta:
    constraints = [
            models.UniqueConstraint(
                fields=['name', 'title', 'position'],
                name="unique_name_title_position"
            ),
        ]

但是,如果titleNone,则此约束不成立。
究其原因,这是因为您可以使用UNIQUE约束将NULL值插入到列中,因为NULL不存在值,所以它永远不等于其他NULL值,也不会被视为重复值,这意味着如果其中一个值为NULL,则可能插入看起来重复的行。
在Django中严格执行这种独特性的正确方法是什么?

2ledvvac

2ledvvac1#

UniqueConstraint不是在Django级别上强制执行的,而是直接在数据库上强制执行的。
例如,PostgreSQL允许多个Null记录具有唯一性,而MSSQL不允许
您可以检查列的每个子集是否为CheckConstraint,但您会发现这很繁琐,因为它要求每个组合都是唯一的indexed
为了避免这种混乱,你可以按照Django的CharField指南来做
避免在基于字符串的字段(如CharField和TextField)上使用null。如果基于字符串的字段的null=True,则意味着它有两个可能的“无数据”值:NULL和空字符串。在大多数情况下,“无数据”有两个可能的值是多余的;“Django约定是使用空字符串,而不是NULL。一个例外是CharField同时设置了unique=True和blank=True。在这种情况下,需要null=True以避免在保存多个空值对象时违反唯一约束。
检查空字符串的唯一性

ckx4rj1h

ckx4rj1h2#

titleNULL时,您只需要add one more constraint

models.UniqueConstraint(
    name='only_one_null',
    fields=('name', 'position'),
                condition=Q(title__isnull=True)
)

这应保证title中NULL值的唯一性。您可以根据需要为NULL值添加更多约束

uemypmqf

uemypmqf3#

你可以选择titleposition中从未出现过的值,并使用如下索引:

CREATE UNIQUE INDEX ON mytable (
   name,
   coalesce(title, '#impossible#'),
   coalesce(position, '#impossible#'),
);

这会将NULL值替换为其他值,从而防止重复。

相关问题