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

Django创建superuser报date_of_birth非空约束失败错误求解决

问题原因

执行python manage.py createsuperuser触发NOT NULL constraint failed: bankapp_userregistermodel.date_of_birth报错,核心是三个问题:

  • 自定义用户管理器的create_user、create_superuser方法仅给用户实例赋值了mobile_number和password,而模型中date_of_birth、bank_ac、first_name等多个字段既没设置null=True允许为空,也没配置默认值,入库时这些字段值为NULL,违反数据库非空约束
  • 模型的REQUIRED_FIELDS配置为空列表,Django执行创建超级用户命令时,只会提示输入USERNAME_FIELD指定的手机号和密码,不会引导用户输入其他必填字段
  • 代码存在多处拼写错误:admin中新增用户表单配置属性名写错、权限判断方法名写错,导致后台配置和权限逻辑不生效;另外原代码中is_admin字段默认值为True,会导致普通注册用户默认拥有管理员权限,属于逻辑bug
修复方案

第一步:修正models.py代码

重点调整用户管理器逻辑支持接收额外字段参数、修正权限方法名、给超级用户场景下的必填字段设置默认值(如果希望创建超管时命令行提示输入指定字段,可将字段名加入REQUIRED_FIELDS列表),修正后代码如下:

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin

class MyuserManager(BaseUserManager):
    def create_user(self, mobile_number, password=None, **extra_fields):
        if not mobile_number:
            raise ValueError("用户必须填写手机号")
        user = self.model(mobile_number=mobile_number, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, mobile_number, password=None, **extra_fields):
        # 给超级用户设置默认权限
        extra_fields.setdefault('is_admin', True)
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_active', True)
        # 给非业务核心的必填字段设置默认值,避免非空约束报错
        extra_fields.setdefault('date_of_birth', '2000-01-01')
        extra_fields.setdefault('bank_ac', 'ADMIN_DEFAULT')
        extra_fields.setdefault('first_name', 'Super')
        extra_fields.setdefault('last_name', 'Admin')
        extra_fields.setdefault('user_name', 'admin')
        extra_fields.setdefault('email', 'admin@local.dev')
        extra_fields.setdefault('address', 'Default Admin Address')
        extra_fields.setdefault('pin_code', 100000)
        
        user = self.create_user(mobile_number, password=password, **extra_fields)
        return user

class UserRegisterModel(AbstractBaseUser, PermissionsMixin):
    mobile_number = models.IntegerField(verbose_name="手机号", unique=True)
    bank_ac = models.CharField(max_length=64, verbose_name="银行卡号")
    first_name = models.CharField(max_length=64, verbose_name="名")
    last_name = models.CharField(max_length=64, verbose_name="姓")
    user_name = models.CharField(max_length=64, verbose_name="用户名")
    email = models.EmailField(verbose_name="邮箱")
    date_of_birth = models.DateField(verbose_name="出生日期")
    address = models.CharField(max_length=160, verbose_name="地址")
    pin_code = models.IntegerField(verbose_name="邮编")
    is_active = models.BooleanField(default=True, verbose_name="是否激活")
    is_staff = models.BooleanField(default=True, verbose_name="是否允许登录后台")
    is_admin = models.BooleanField(default=False, verbose_name="是否管理员")
    date_joined = models.DateTimeField(default=timezone.now, verbose_name="注册时间")

    objects = MyuserManager()

    USERNAME_FIELD = "mobile_number"
    # 需要创建超管时命令行提示输入的字段可加在下方列表,例如['email', 'date_of_birth']
    REQUIRED_FIELDS = []

    def __str__(self):
        return str(self.mobile_number)

    def has_perm(self, perm, obj=None):
        return self.is_admin

    # 原方法名少了末尾s,和Django内置权限方法不匹配,已修正
    def has_module_perms(self, app_label):
        return self.is_admin

    @property
    def is_superuser(self):
        return self.is_admin

第二步:修正admin.py代码

重点修正add_fieldsets的拼写错误(原代码多写了一个s),移除列表中的password字段避免泄露密码哈希,修正新增用户表单的密码字段名,修正后代码如下:

from django.contrib import admin
from bankapp.models import UserRegisterModel
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

class UserAdmin(BaseUserAdmin):
    list_display = ['bank_ac','first_name','last_name','user_name','mobile_number','email','date_of_birth','address','pin_code']
    list_filter = ['is_admin']
    search_fields = ['mobile_number', 'user_name']
    ordering = ['mobile_number']
    filter_horizontal = []
    fieldsets = []
    # 修正属性名拼写
    add_fieldsets = [
        [None, {
            'classes' : ['wide',],
            # Django内置新增用户表单使用password1、password2作为两次密码输入字段
            'fields' : ['mobile_number','email','password1', 'password2', 'date_of_birth'],
        }],
    ]
admin.site.register(UserRegisterModel, UserAdmin)

第三步:重新生成并执行数据库迁移

在项目根目录执行以下命令:

python manage.py makemigrations
python manage.py migrate

如果迁移时提示历史冲突,先删除bankapp/migrations/目录下除__init__.py外的所有文件,再重新执行上述两条命令即可。
完成后重新执行python manage.py createsuperuser就能正常创建超级用户,不会触发非空约束报错。

内容的提问来源于stack exchange,提问作者K Srikanth Varma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 12:48:15