最近在使用django框架的过程中发现一个问题,即标题所写的“Field ‘X’ doesn't have a default value”,具体的migrations代码如下:
migrations.AddField(
model_name="test",
name="user_name",
field=models.CharField(default='xxx', max_length=64, null=True)
)
这段代码的本意是在test表里新増一个字段user_name,默认值是xxx,值允许为空,执行如下命令使之生效:
django-admin migrate [app_label] [migration_name]
然后通过程序执行insert语句,当不写user_name字段时,原以会插入NULL值,可是却报了异常:Field 'user_name' doesn't have a default value。
查看数据库表,该字段也是允许为NULL。
show create table test;
得到如下结果:
create table test (
`user_name` varchar(64),
...
)
关于建表时字段的NULL,NOT NULL设置,mysql create table 官方文档如是说:
NOT NULL | NULL
If neither NULL nor NOT NULL is specified, the column is treated as though NULL had been specified.
In MySQL 5.7, only the InnoDB, MyISAM, and MEMORY storage engines support indexes on columns that can have NULL values. In other cases, you must declare indexed columns as NOT NULL or an error results.
经过测试,效果确实如其所说,执行插入语句,不写user_name字段时,插入值为NULL。
无奈,只得完整还原django的migrate了,利用sqlmigrate:
django-admin sqlmigrate app_label migration_name
得到开头migration的确切sql:
alter table `test` add column `user_name` varchar(64) default 'xxx' NULL;
alter table `test` alter column 'user_name' drop default;
事情到了这里,似乎明了了,因为它drop default嘛,但是再看 mysql alter table 官方文档,如下:
ALTER ... SET DEFAULT or ALTER ... DROP DEFAULT specify a new default value for a column or remove the old default value, respectively. If the old default is removed and the column can be NULL, the new default is NULL. If the column cannot be NULL, MySQL assigns a default value as described in Section 11.6, “Data Type Default Values”.
意思是说,如果drop default之后,该字段允许为NULL,则NULL为其默认值。
如果照上面所述,则不应该报“Field ‘X’ doesn't have a default value”,可是现实却很打脸。
所以,这难道是mysql的一个BUG?抑或?
最后,问题的解决也很简单,给该字段重新设置一个默认值即可,比如设置为NULL。