Postrgersql + Django:NULL值导致IntegrityError:重复键值违反唯一约束

时间:2014-01-31 01:09:24

标签: django postgresql null

我有下表:

   Column      |            Type             |                           Modifiers                           
----------------+-----------------------------+---------------------------------------------------------------
user_id         | bigint                      | not null default nextval('employee_user_id_seq'::regclass) 
name            | character varying(50)       | not null                                                      
phonenumber     | character varying(20)       | not null                                                      
phonenumber2    | character varying(20)       |                                                               
email           | character varying(75)       |      
Indexes:
"employee_pkey" PRIMARY KEY, btree (user_id)
"employee_email_key" UNIQUE CONSTRAINT, btree (email)
"employee_phonenumber2_key" UNIQUE CONSTRAINT, btree (phonenumber2)
"employee_phonenumber_email_key" UNIQUE CONSTRAINT, btree (phonenumber, email)
"employee_phonenumber_key" UNIQUE CONSTRAINT, btree (phonenumber)                                                         

在models.py中:

class Employee(models.Model):
    user_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    phonenumber = models.CharField(max_length=20, unique=True)
    phonenumber2 = models.CharField(max_length=20, unique=True)
    email = models.EmailField(blank=True, unique=True)

使用Django我已经将没有phonenumber2的Employee插入到表中。第一次它顺利导致它是第一个NULL然后在第二次尝试我得到错误:

IntegrityError: duplicate key value violates unique constraint "employee_phonenumber2_key"
DETAIL:  Key (phonenumber2)=() already exists.

根据我的理解,NULL不应被视为约束的值,我想要实现的是,不同员工不能复制相同的电话号码或电话号码和电子邮件的组合。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

您根本不是真正插入NULL,而是插入空字符串''。如果您插入NULL,则无法获得您显示的错误。如果您希望使用唯一约束来忽略NULL,则必须实际使用NULL

如果检查PostgreSQL服务器错误日志,您将看到运行的查询;但是,您可能需要打开log_statement = all以获取所有详细信息。它会显示INSERT '' phonenumber2 NULL而不是ALTER TABLE employee ADD CONSTRAINT phonenumber2_nonempty CHECK (phonenumber2 IS NULL OR length(phonenumber2) > 0);

最后证明:

None

它将拒绝任何长度为零的字符串。包括您已经添加的那个您认为为null的那个,因此添加检查约束将失败。

你似乎在使用Django,提到你的“models.py”。 Django的IMO很不认为Python值''应该存储在字符字段中NULL,而不是'';它将None''都视为“空值”。 You can tell it to store None as NULL with Field.null。我不确定它是否会强制NULL存储为{{1}};我希望不是,但没有经过测试。