我有Foo模型,其中有栏杆。bar字段应该是唯一的,但允许为空,这意味着如果bar字段为null,我想允许多个记录,但如果不是,null则值必须是唯一的。
null
这是我的模型:
class Foo(models.Model): name = models.CharField(max_length=40) bar = models.CharField(max_length=40, unique=True, blank=True, null=True, default=None)
这是该表的相应SQL:
CREATE TABLE appl_foo ( id serial NOT NULL, "name" character varying(40) NOT NULL, bar character varying(40), CONSTRAINT appl_foo_pkey PRIMARY KEY (id), CONSTRAINT appl_foo_bar_key UNIQUE (bar) )
当使用管理界面在bar为null的情况下创建多个1个foo对象时,它给我一个错误:“此Bar的Foo已经存在。”
但是,当我插入数据库(PostgreSQL)时:
insert into appl_foo ("name", bar) values ('test1', null) insert into appl_foo ("name", bar) values ('test2', null)
这样做很好,它允许我插入1条以上且bar为null的记录,因此数据库允许我执行我想要的操作,这是Django模型的错误。有任何想法吗?
编辑
就数据库而言,解决方案的可移植性不是问题,我们对Postgres感到满意。我尝试过设置可调用对象的唯一性,这是我的函数针对bar的特定值返回True / False ,它没有给出任何错误,但是接缝就像根本没有任何作用。
到目前为止,我已经从bar属性中删除了唯一的说明符,并在应用程序中处理了bar的唯一性,但是仍在寻找更优雅的解决方案。有什么建议吗?
自从票务#9039被修复以来,Django就唯一性检查的目的没有将NULL视为NULL,请参阅:
http://code.djangoproject.com/ticket/9039
这里的问题是,表单CharField的规范化“空白”值是一个空字符串,而不是无。因此,如果将该字段保留为空白,则会得到一个空字符串,而不是NULL,存储在数据库中。在Django和数据库规则下,空字符串等于用于唯一性检查的空字符串。
你可以通过使用clean_bar方法为Foo提供自己的自定义模型表单,从而将空字符串转换为None,从而强制管理界面为空字符串存储NULL:
class FooForm(forms.ModelForm): class Meta: model = Foo def clean_bar(self): return self.cleaned_data['bar'] or None class FooAdmin(admin.ModelAdmin): form = FooForm