Django admin后台,修改User表数据时,遇到报错:
django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`auto_center`.`django_admin_log`, CONSTRAINT `django_admin_log_user_id_c564eba6_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`))')
网上查了下,基本上都是说修改setting文件的databases,添加以下代码取消外键检查:
'OPTIONS': {
"init_command": "SET foreign_key_checks = 0;",
}
但是,取消外键检查,会导致外键约束检查失效,会有隐患,乃是治标不治本的方法。
看报错的信息,是django_admin_log表的user_id,指向了外键是auth_user。但我的Django User模型有个扩展表,是指向了扩展的User表,而非Django原生的auth_user表。
查看django_admin_log源码,是指向settings.AUTH_USER_MODEL的。而我在settings里,已经配置过指向扩展User表了:
AUTH_USER_MODEL = 'auth.ExpandUser'
配置是生效的。我切换到测试环境,是不会有上面报错了,相同代码,只是切换了数据库,就会有报错。说明不是代码问题。
仔细思考了下,应该是线上环境,比较久远了,当初执行migrate的时候,django_admin_log表的user_id,指向了原生的auth_user。后来更新了扩展User表,测试环境的数据库是重新建立过的,重新执行的migrate,所以关联的外键是扩展User表,不会报错。
所以问题的原因必然是在现有的线上数据库的记录上。查了一圈,找到原因。是django_admin_log表的user_id字段,关联了外键auth_user。而测试环境的是关联的扩展User表。
在这里的引用表,修改成ExpandUser表。再回到admin后台修改User表数据 ,不再报错。
反思一下:之前一直是用Django的ORM管理映射关系的,不知道MySQL原生的外键是怎么管理的。今天遇到的问题,排查下来,就是由于历史的migrate记录,导致扩展User表的时候,数据库还记录旧的外键关系。而admin操作修改的时候,会记录日志到django_admin_log,记录user_id的时候,使用ExpandUser表的user_id记录到数据库时,触发了MySQL检查外键,指向auth_user表,而auth_user没有对应的user_id,就报错了。
知道原因,再回过头来看修复方法,就很简单了:
- 修改django_admin_log,把user_id关联的外键,改成自己定义的扩展User表
- 如果不想改,可以在测试环境(或新建个空的数据库),重新执行迁移,然后把新的django_admin_log表,通过数据库复制的方式,覆盖掉现有的django_admin_log表
|