You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:44:54