项目中期从AbstractUser切换到AbstractBaseUser移除username字段遇阻求助
Django自定义用户模型问题解决
问题背景
- 用
AbstractUser扩展用户模型,设置以email作为认证字段,但AbstractUser仍强制依赖username字段 - 模型里设
username=None,执行makemigrations时报错:CustomUser指定了未知字段'username' - 换成继承
AbstractBaseUser后,执行迁移还是报同样的错误 - 删掉
username=None能通过迁移,但创建用户时is_valid()校验失败,表单提示username必填且不能为null
代码文件
models.py
# 请粘贴你的models代码到这里
forms.py
# 请粘贴你的forms代码到这里
admin.py
# 请粘贴你的admin代码到这里
解决方案
1. 处理username字段依赖问题
方案一:继续使用AbstractUser
不需要设置username=None,直接重写username字段并配置认证参数即可:
from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): email = models.EmailField(unique=True) # 将username设为可选字段 username = models.CharField(max_length=150, blank=True, null=True) # 指定email作为用户认证的唯一字段 USERNAME_FIELD = 'email' # 移除username,只保留必要的必填字段 REQUIRED_FIELDS = []
同时修改用户创建表单,排除username字段:
from django.contrib.auth.forms import UserCreationForm from .models import CustomUser class CustomUserCreationForm(UserCreationForm): class Meta: model = CustomUser fields = ('email', 'password1', 'password2')
方案二:切换到AbstractBaseUser
完全自定义用户模型,不需要处理username字段,但必须实现必要的用户管理器和基础方法:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models # 自定义用户管理器,处理用户创建逻辑 class CustomUserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError('必须填写邮箱地址') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password=None, **extra_fields): extra_fields['is_staff'] = True extra_fields['is_superuser'] = True return self.create_user(email, password, **extra_fields) # 自定义用户模型 class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] objects = CustomUserManager() def get_full_name(self): return self.email def get_short_name(self): return self.email
2. 切换继承类的迁移注意事项
从AbstractUser切换到AbstractBaseUser必须清理旧迁移和相关数据,步骤如下:
- 删除项目所有
migrations目录下的迁移文件(保留__init__.py) - 清空数据库中的
CustomUser表,同时删除django_migrations表中与该模型相关的迁移记录 - 重新执行迁移命令:
python manage.py makemigrations python manage.py migrate
注意:生产环境操作前必须备份数据,或编写数据迁移脚本将旧用户数据导入新模型
内容的提问来源于stack exchange,提问作者Topher76
相关产品推荐
相关产品推荐

