[英]Django unique together constraint failure?
使用Django 1.5.1。 Python 2.7.3。
我想用外鍵字段和段塞字段做一個唯一的約束約束。 所以在我的模型元中,我做到了
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的foreign_key和重復的字符串。
例如,
我可以輸入並保存
# 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_together之后,為什么我仍然可以輸入三個相同值的行?
我現在只是猜測它可能與foreign_key字段的默認值None有關,因為在unique_together之前,當我在slug上有unique = True時,一切正常。 因此,如果是這種情況,我應該具有哪個默認值表示空值,還保持唯一約束?
在Postgresql中, NULL
不等於任何其他NULL
。 因此,您創建的行不同(從Postgres的角度來看)。
更新
你有幾種方法來處理它:
Null
值並使用一些默認值 save
方法以檢查是否存在此類行 為模型添加一個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")
注意,默認save
方法不會調用clean
(或full_clean
)。
注意:如果您將此代碼放在save
方法中,更新表單(如在管理員中)將不起作用:由於ValidationError
異常,您將遇到跟蹤錯誤。
只需在slug
字段上手動創建二級索引,但僅限於foreign_key_id
NULL值:
CREATE INDEX table_name_unique_null_foreign_key
ON table_name (slug) WHERE foreign_key_id is NULL
請注意,Django不支持此功能,因此如果沒有自定義表單/模型驗證,您將獲得純IntegrityError / 500。
使用空列創建唯一約束的可能重復
正如業余愛好者所說,“在Postgresql中NULL不等於任何其他NULL。因此你創建的行不一樣(從Postgres的角度來看)。”
解決此挑戰的另一種可能方法是在form_valid方法中的視圖級別添加自定義驗證。
在views.py中:
def form_valid(self, form): --OTHER VALIDATION AND FIELD VALUE ASSIGNMENT LOGIC-- if ModelForm.objects.filter(slug=slug,foreign_key=foreign_key: form.add_error('field', forms.ValidationError( _("Validation error message that shows up in your form. "), code='duplicate_row', )) return self.form_invalid(form)
如果您使用基於類的視圖,此方法很有用,尤其是在您自動將值分配給要從用戶隱藏的字段時。
優點:
缺點: - 這不能防止直接在數據庫級別創建的重復行。 - 如果您使用Django的管理后端來創建新的MyModel對象,則需要將相同的驗證邏輯添加到您的管理表單中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.