Django自定义NewUser用户模型执行数据库迁移报ValueError咨询
Django自定义用户模型迁移懒引用报错修复方案
报错信息
ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'user.newuser', but app 'user' doesn't provide model 'newuser'. The field user.UserInfo.user was declared with a lazy reference to 'user.newuser', but app 'user' doesn't provide model 'newuser'.
问题根因
报错是迁移依赖链断裂导致:你之前的0015_delete_newuser迁移已经将NewUser模型标记为删除状态,但Django内置的admin.LogEntry模型、你自建的UserInfo模型仍然保留着对user.NewUser的外键懒引用,新建NewUser的迁移没有同步更新这些外键关联,就会触发找不到模型的错误。另外你的现有代码存在3个会引发后续功能异常的bug,需要先修复。
修复步骤
1. 先修复模型代码bug
- 修复
CustomAccountManager的create_superuser方法:原方法存在参数顺序错位、调用create_user无返回值两个问题,修正后代码如下:
def create_superuser(self, email, first_name, last_name, phone_number, password, **other_fields): other_fields.setdefault('is_staff', True) other_fields.setdefault('is_superuser', True) other_fields.setdefault('is_active', True) if other_fields.get('is_staff') is not True: raise ValueError(_('Superuser must be assigned to is_staff=True')) if other_fields.get('is_active') is not True: raise ValueError(_('Superuser must be assigned to is_active=True')) if other_fields.get('is_superuser') is not True: raise ValueError(_('Superuser must be assigned to is_superuser=True')) # 修正参数顺序和create_user入参对齐,添加return返回创建的用户实例 return self.create_user(first_name, last_name, phone_number, email, password, **other_fields)
- 删除NewUser模型里多余的字段:
AbstractBaseUser已经内置了password字段,不需要重复定义;confirm_password是表单校验层字段,不应该放在模型层,直接删掉这两个字段的定义即可。
2. 清理断裂的迁移记录(开发环境推荐方案,无残留问题)
- 删除
user应用下migrations文件夹中除__init__.py之外的所有文件 - 如果home、pages、reservation等其他应用存在关联用户模型的外键,同步删除这些应用
migrations文件夹中除__init__.py之外的所有文件 - 删除本地数据库文件(开发环境默认是
db.sqlite3,使用MySQL/PostgreSQL的话直接删除对应库后重建空库即可)
3. 重新生成并执行迁移
按顺序执行以下命令:
# 优先生成用户应用的初始迁移 python manage.py makemigrations user # 生成其余应用的迁移 python manage.py makemigrations # 执行全量迁移 python manage.py migrate
迁移执行完成后,再执行python manage.py createsuperuser创建管理员账号即可正常使用。
生产环境替代方案(不删库/不删迁移场景)
如果是生产环境不能清空数据,可以直接修改你当前创建NewUser的迁移文件,在CreateModel操作之后追加两个外键更新操作,同步修正懒引用指向:
operations = [ migrations.CreateModel( # 你原有的NewUser创建逻辑保持不变 name='NewUser', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('first_name', models.CharField(blank=True, max_length=200, null=True)), ('last_name', models.CharField(blank=True, max_length=200, null=True)), ('email', models.EmailField(blank=True, max_length=200, null=True, unique=True)), ('phone_number', models.CharField(blank=True, max_length=10, null=True)), ('address', models.TextField(blank=True, null=True)), ('pin_code', models.CharField(blank=True, max_length=6, null=True)), ('region', models.CharField(blank=True, max_length=200, null=True)), ('state', models.CharField(blank=True, max_length=100, null=True)), ('start_date', models.DateField(default=django.utils.timezone.now)), ('is_staff', models.BooleanField(default=False)), ('is_active', models.BooleanField(default=False)), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), ], options={'abstract': False,}, ), # 追加以下两个操作更新关联外键 migrations.AlterField( model_name='logentry', name='user', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user'), ), migrations.AlterField( model_name='userinfo', name='user', field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), ]
修改完成后再执行python manage.py migrate即可正常完成迁移。
内容的提问来源于stack exchange,提问作者Roshan
相关产品推荐
相关产品推荐

