使用AbstractBaseUser自定义用户模型时手动创建用户密码未哈希
问题分析与解决方案
核心问题1:Manager类方法缩进错误
你的managers.py中,_create_user、create_user、create_superuser三个方法没有缩进在UserManager类内部,导致这些方法是全局函数而非类的成员方法。这意味着你的UserManager实际上没有重写父类方法,调用User.objects.create_user时,实际用的是BaseUserManager的默认实现,自定义逻辑完全没生效。
核心问题2:_create_user逻辑存在覆盖问题
原_create_user里的三个if分支独立执行,如果同时传入多个字段(比如email+phone+is_superuser=True),后面的if会重新实例化user对象,覆盖前面的字段设置,导致email、phone丢失,逻辑混乱。
修复后的代码
managers.py
from django.contrib.auth.base_user import BaseUserManager class UserManager(BaseUserManager): use_in_migrations = True def _create_user(self, username=None, email=None, phone=None, password=None, **extra_fields): """ Creates and saves a User with the given email/phone and password. """ # 校验必填逻辑 if not username: if not email and not phone: raise ValueError('The given email/phone must be set') # 初始化用户数据字典 user_data = {**extra_fields} if username: user_data['username'] = username # 处理邮箱字段 if email: email = self.normalize_email(email) user_data['email'] = email if not username: user_data['username'] = email # 处理手机号字段 if phone: user_data['phone'] = phone if not username: user_data['username'] = phone # 实例化用户并设置哈希密码 user = self.model(**user_data) user.set_password(password) user.save(using=self._db) return user def create_user(self, username, email=None, phone=None, password=None, **extra_fields): extra_fields.setdefault('is_superuser', False) return self._create_user(username=username, email=email, phone=phone, password=password, **extra_fields) def create_superuser(self, username, password, **extra_fields): extra_fields.setdefault('is_superuser', True) extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_active', True) if extra_fields.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self._create_user( username=username, password=password, **extra_fields )
关键注意点
手动创建用户时,必须使用User.objects.create_user()方法,绝对不能直接用User.objects.create()。因为create()会直接把明文密码存入数据库,不会调用set_password()做哈希处理。正确调用示例:
# 正确方式 User.objects.create_user(username='test_user', email='test@example.com', password='123456') # 错误方式(密码不会哈希) User.objects.create(username='test_user', email='test@example.com', password='123456')
额外优化建议
- 你的
User模型中REQUIRED_FIELDS = ['email'],但自定义create_user允许email为None,建议保持逻辑一致,要么修改REQUIRED_FIELDS,要么在create_user中添加邮箱校验。 - 模型中的
unique_together = ('username', 'phone')意义不大,因为username已经是唯一字段,可考虑移除该约束。
内容的提问来源于stack exchange,提问作者Muhtar
相关产品推荐
相关产品推荐

