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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 22:15:36