Django创建超级用户触发IntegrityError问题求助
Django自定义邮箱登录用户模型创建超级用户报IntegrityError的解决办法
问题原因
你遇到的IntegrityError本质是自定义用户模型未正确处理username字段的唯一约束:
- Django默认
AbstractUser中的username是唯一且非空字段,当你改成用邮箱登录时,若仅设置username=null=True但未取消其unique=True属性,数据库会保留username的唯一约束。 - PostgreSQL中空值被视为唯一值,若数据库中已存在一条
username为空的用户记录,再次创建超级用户时,新用户的username默认会被设为空,直接触发唯一约束冲突。
解决步骤
方案1:基于AbstractUser改造(保留username字段但取消唯一约束)
适合不想完全重构用户模型的场景:
- 修改
accounts/models.py中的CustomUser类:from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): # 取消username的唯一约束,允许为空 username = models.CharField(max_length=150, blank=True, null=True, unique=False) # 设置邮箱为唯一标识 email = models.EmailField(unique=True) # 指定用邮箱作为登录用户名 USERNAME_FIELD = 'email' # 超级用户创建时无需额外必填字段(邮箱已作为USERNAME_FIELD) REQUIRED_FIELDS = [] - 执行数据库迁移:
py manage.py makemigrations py manage.py migrate - 清理现有冲突数据(如果数据库已有空username记录):
进入Django Shell执行:py manage.py shell from accounts.models import CustomUser # 删除所有username为空的用户 CustomUser.objects.filter(username__isnull=True).delete() - 重新创建超级用户:
py manage.py createsuperuser
方案2:基于AbstractBaseUser重构(完全移除username字段)
适合彻底用邮箱作为用户唯一标识的场景:
- 修改
accounts/models.py,自定义用户管理器和模型: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): # 超级用户默认开启staff和superuser权限 extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(email, password, **extra_fields) class CustomUser(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True, verbose_name='邮箱') is_active = models.BooleanField(default=True, verbose_name='是否激活') is_staff = models.BooleanField(default=False, verbose_name='是否为后台管理员') date_joined = models.DateTimeField(auto_now_add=True, verbose_name='注册时间') # 绑定自定义管理器 objects = CustomUserManager() # 指定邮箱为登录字段 USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] - 执行迁移并创建超级用户:
py manage.py makemigrations py manage.py migrate py manage.py createsuperuser
配套代码调整
表单(forms.py)
确保用户相关表单使用自定义模型:
from django.contrib.auth.forms import UserCreationForm, UserChangeForm from .models import CustomUser class CustomUserCreationForm(UserCreationForm): class Meta: model = CustomUser fields = ('email',) class CustomUserChangeForm(UserChangeForm): class Meta: model = CustomUser fields = ('email', 'is_staff', 'is_active')
登录视图(views.py)
自定义登录表单,让用户输入邮箱登录:
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import login from django.shortcuts import render, redirect class EmailLoginForm(AuthenticationForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 把表单中的"用户名"标签改为"邮箱" self.fields['username'].label = '邮箱' def user_login(request): if request.method == 'POST': form = EmailLoginForm(request, data=request.POST) if form.is_valid(): login(request, form.get_user()) return redirect('home') # 替换为你的首页路由 else: form = EmailLoginForm() return render(request, 'accounts/login.html', {'form': form})
关键配置检查
确保settings.py中已指定自定义用户模型:
AUTH_USER_MODEL = 'accounts.CustomUser'
内容的提问来源于stack exchange,提问作者Rcacodedev
相关产品推荐
相关产品推荐

