自定义Django User模型后,后台创建用户报UNIQUE约束错误求助
问题排查与解决:Django自定义User模型创建用户报唯一约束错误
问题原因
- 自定义
User模型继承了AbstractUser,该父模型默认包含username字段,且自带唯一约束(unique=True) - 虽然将
USERNAME_FIELD指定为email,但创建用户时未给username字段赋值,导致所有新创建的用户username均为空字符串 - 重复插入空字符串触发唯一约束校验,抛出
django.db.utils.IntegrityError: UNIQUE constraint failed: users_user.username错误
解决方法
方法一:自动填充username字段
在models.py的User类中,重写username字段并添加自动填充逻辑,确保每个用户的username唯一:
from django.db import models from django.contrib.auth.models import AbstractUser, PermissionsMixin from .managers import UserManager class User(AbstractUser, PermissionsMixin): email = models.EmailField(unique=True) name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # 重写username字段,确保唯一且自动填充 username = models.CharField(max_length=150, unique=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] objects = UserManager() def save(self, *args, **kwargs): # 若username为空,用email填充(也可使用UUID等唯一值) if not self.username: self.username = self.email super().save(*args, **kwargs) def __str__(self): return self.name
方法二:改用AbstractBaseUser移除username字段(推荐)
如果不需要username字段,直接继承AbstractBaseUser(而非AbstractUser),避免父模型自带的username字段:
from django.db import models from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin from .managers import UserManager class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] objects = UserManager() def __str__(self): return self.name
补充:修复UserManager中的冗余代码
原create_user方法中直接传入password到模型构造器属于冗余操作,且可能导致密码处理异常,修改为:
from django.contrib.auth.models import UserManager from django.utils.translation import gettext_lazy as _ class CustomUserManager(UserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError(_('The Email field must be set')) # 标准化邮箱格式 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, **extra_fields): extra_fields.setdefault("is_staff", True) extra_fields.setdefault("is_superuser", True) extra_fields.setdefault("is_active", True) if extra_fields.get("is_staff") is not True: raise ValueError(_("Superuser must have is_staff=True.")) if extra_fields.get("is_superuser") is not True: raise ValueError(_("Superuser must have is_superuser=True.")) return self.create_user(email, password, **extra_fields)
注意事项
- 修改模型后,需执行数据库迁移:
python manage.py makemigrations和python manage.py migrate - 若使用方法二,当前的
CustomUserAdmin配置无需额外修改,已适配AbstractBaseUser模型
内容的提问来源于stack exchange,提问作者hossein siadati
相关产品推荐
相关产品推荐

