Django unique together约束失败?

2024-04-29 00:59:20 发布

您现在位置:Python中文网/ 问答频道 /正文

使用Django 1.5.1。Python2.7.3。

我想用外键场和slug场做一个独特的together约束。所以在我的模型meta中,我做到了

foreign_key = models.ForeignKey("self", null=True, default=None)
slug = models.SlugField(max_length=40, unique=False)

class Meta:
    unique_together = ("foreign_key", "slug")

我甚至检查了Postgres(9.1)中的表描述,并将约束放入数据库表中。

-- something like
"table_name_foreign_key_id_slug_key" UNIQUE CONSTRAINT, btree (foreign_key_id, slug)

但是,我仍然可以将None/null和重复字符串的外键保存到数据库表中。

例如

我可以输入和保存

# model objects with slug="python" three times; all three foreign_key(s) 
# are None/null because that is their default value
MO(slug="python").save()
MO(slug="python").save()
MO(slug="python").save()

所以在一起使用unique_之后,为什么我仍然可以输入三个相同值的行?

我现在只是猜测,这可能与foreign_key字段的默认值None有关,因为在unique_一起出现之前,当我在slug上只有unique=True时,一切正常。如果是这样的话,我应该有什么默认值来表示空值,同时还保持唯一的约束?


Tags: keynoneid数据库truedefaultmodelssave
3条回答

在Postgresql中NULL不等于任何其他NULL。因此,您创建的行不相同(从Postgres的角度来看)。

更新

你有几种方法来处理它:

  • 禁止外键的Null值,并使用一些默认值
  • 重写模型的save方法以检查不存在此类行
  • 更改SQL标准:)

向模型中添加clean方法,以便可以编辑现有行。

def clean(self):
    queryset = MO.objects.exclude(id=self.id).filter(slug=self.slug)
    if self.foreign_key is None:
        if queryset.exists():
            raise ValidationError("A row already exists with this slug and no key")
    else:
        if queryset.filter(foreign_key=self.foreign_key).exists():
            raise ValidationError("This row already exists")

注意,clean(或full_clean)不是由默认的save方法调用的。

注意:如果将此代码放在save方法中,则更新表单(如在管理中)将不起作用:由于ValidationError异常,将出现回溯错误。

只需在slug字段上手动创建二级索引,但仅限于foreign_key_id中的空值:

CREATE INDEX table_name_unique_null_foreign_key
  ON table_name (slug) WHERE foreign_key_id is NULL

请注意,Django不支持此功能,因此如果不进行自定义表单/模型验证,您将得到纯完整性错误/500。

可能与Create unique constraint with null columns重复

相关问题 更多 >