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
相关产品推荐
相关产品推荐

