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

Django用户注册报错:UNIQUE constraint failed: accounts_user.username

Django注册时IntegrityError错误解决指南

问题原因

自定义User模型中定义了username字段并设置为unique=True,但注册表单UserCreationForm未包含该字段,且模型未给username设置默认值或允许为空。提交注册请求时,username字段会被存入空字符串,若数据库中已存在空字符串的username记录(比如之前测试残留),或首次注册时模型未正确赋值username,都会触发数据库唯一约束冲突。

解决方法

方法1:移除不必要的username字段

既然已将email设为登录标识(USERNAME_FIELD),若不需要username字段,直接删除:

  1. 修改accounts/models.py中的User模型:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin

class UserManager(BaseUserManager):
    def create_user(self, email, password1=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(password1)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password1=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password1, **extra_fields)

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(verbose_name="email", max_length=60, unique=True)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    # 移除username字段
    date_joined = models.DateTimeField(verbose_name="date joined", auto_now_add=True)
    last_login  = models.DateTimeField(verbose_name="last login", auto_now=True)
    is_admin   = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name']

    def __str__(self):
        return self.email
  1. 执行数据库迁移:
python manage.py makemigrations
python manage.py migrate

方法2:让用户输入username(保留字段)

若需要保留username字段,修改表单让用户输入:

  1. 修改accounts/forms.py,添加username到表单字段:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User

class UserCreationForm(UserCreationForm):
    class Meta:
        model = User
        fields = ['email', 'username', 'first_name', 'last_name', 'password1', 'password2']
  1. 注册模板register.html会自动渲染username输入框(无需修改模板),表单会自动验证username的唯一性。

方法3:自动生成唯一username(无需用户输入)

若要保留username字段但不让用户输入,可在创建用户时自动生成唯一值:

  1. 修改accounts/models.py中的UserManager:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
import random
import string

class UserManager(BaseUserManager):
    def create_user(self, email, password1=None, **extra_fields):
        if not email:
            raise ValueError('The Email field must be set')
        email = self.normalize_email(email)
        # 基于邮箱前缀生成唯一username
        base_username = email.split('@')[0]
        username = base_username
        # 检查唯一性,重复则添加随机后缀
        while self.model.objects.filter(username=username).exists():
            suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4))
            username = f"{base_username}_{suffix}"
        extra_fields['username'] = username
        
        user = self.model(email=email, **extra_fields)
        user.set_password(password1)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password1=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password1, **extra_fields)
  1. 保持原表单代码不变,用户注册时系统会自动生成唯一username。

内容的提问来源于stack exchange,提问作者Joseynice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:23:18