自定义User模型中create_superuser命令执行失败的问题
问题描述
执行python manage.py createsuperuser创建超级用户时,触发如下错误:
Traceback (most recent call last): File "C:\Users\acer\Desktop\prod\DirCom\DirCom\manage.py", line 22, in <module> main() File "C:\Users\acer\Desktop\prod\DirCom\DirCom\manage.py", line 18, in main execute_from_command_line(sys.argv) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\core\management\__init__.py", line 446, in execute_from_command_line utility.execute() File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\core\management\__init__.py", line 440, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\core\management\base.py", line 402, in run_from_argv self.execute(*args, **cmd_options) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 88, in execute return super().execute(*args, **options) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\core\management\base.py", line 448, in execute output = self.handle(*args, **options) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 183, in handle validate_password(password2, self.UserModel(**fake_user_data)) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\db\models\base.py", line 561, in __init__ _setattr(self, field.name, rel_obj) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 338, in __set__ super().__set__(instance, value) File "C:\Users\acer\Desktop\prod\DirCom\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 235, in __set__ raise ValueError( ValueError: Cannot assign "1": "User.persona" must be a "Persona" instance.
场景说明:自定义了User模型,与Persona为一对一关联,且将persona加入REQUIRED_FIELDS,执行命令前已通过脚本创建ID为1的Persona实例。
问题根源
Django默认的createsuperuser命令在验证密码时,会构造包含用户输入原始值的fake_user_data字典(比如输入的"1"是字符串类型),然后用self.UserModel(**fake_user_data)创建临时用户实例。但User.persona是OneToOneField,要求传入Persona实例而非ID字符串,因此触发赋值错误。
解决方案
方法一:修改User模型的__init__方法,兼容ID输入
在User模型中重写__init__方法,自动处理ID到Persona实例的转换:
class User(AbstractBaseUser, PermissionsMixin): # 原有模型字段定义... def __init__(self, *args, **kwargs): # 处理persona字段的ID输入 if 'persona' in kwargs and not isinstance(kwargs['persona'], Persona): try: persona_id = int(kwargs['persona']) kwargs['persona'] = Persona.objects.get(pk=persona_id) except (ValueError, Persona.DoesNotExist): raise ValueError("Persona不存在或ID无效") super().__init__(*args, **kwargs)
方法二:自定义createsuperuser命令,绕过默认验证逻辑
创建自定义命令替换默认的createsuperuser流程:
- 在你的App目录下创建
management/commands文件夹,新建createsuperuser.py文件:
from django.contrib.auth.management.commands.createsuperuser import Command as BaseCommand from django.contrib.auth import get_user_model from your_app.models import Persona # 替换为你的App名称 User = get_user_model() class Command(BaseCommand): def handle(self, *args, **options): # 获取用户输入的用户名 username = self.get_input_data(self.username_field, options) # 获取用户输入的Persona ID persona_input = self.get_input_data('persona', options) # 验证Persona存在 try: persona = Persona.objects.get(pk=persona_input) except Persona.DoesNotExist: self.stderr.write(f"Persona con ID {persona_input} no existe") return # 处理密码输入 password = options.get('password') if not password: password = self.get_password() if password != self.get_password_confirmation(): self.stderr.write("Las contraseñas no coinciden") return # 创建超级用户 User.objects.create_superuser( username=username, persona=persona, password=password, **options ) self.stdout.write(f"Superusuario creado correctamente para Persona {persona}")
- 确保你的App已加入
INSTALLED_APPS,重新执行python manage.py createsuperuser即可。
额外修正:UserManager的create_user方法
原create_user方法缺少返回值,修正如下:
def create_user(self, username, persona, password=None, **extra_fields): return self._create_user(username, persona.id, password, False, False, **extra_fields)
验证
执行python manage.py createsuperuser,输入已存在的Persona ID,即可正常创建超级用户。
内容的提问来源于stack exchange,提问作者Angel Alemany
相关产品推荐
相关产品推荐

