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

Django自定义用户模型密码存独立表,request.user报password字段不存在错误

解决Django自定义用户模型密码分离存储导致的ProgrammingError

问题根源

你继承的AbstractBaseUser父类默认自带password字段,Django的ORM会自动把这个字段加到查询语句中,但你的users表并未定义该字段,因此触发了字段不存在的错误。

解决步骤

1. 覆盖父类的password字段

在自定义User模型中显式将password设为None,告知Django该字段无需映射到数据库:

class User(AbstractBaseUser, PermissionsMixin):
    # 你的自定义字段示例
    email = models.EmailField(unique=True, verbose_name='邮箱')
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    
    # 覆盖父类password字段,不存储到数据库
    password = None

2. 关联密码存储表

建立User与UserCredential的一对一关联,确保能从关联表中获取/设置密码:

class UserCredential(models.Model):
    user = models.OneToOneField('User', on_delete=models.CASCADE, related_name='credential')
    password = models.CharField(max_length=128)

class User(AbstractBaseUser, PermissionsMixin):
    # ... 其他字段及password = None
    
    # 关联密码存储表,允许空值方便用户创建后补设密码
    credential = models.OneToOneField(UserCredential, on_delete=models.CASCADE, related_name='user', null=True, blank=True)
    
    # 指定用户身份验证的唯一字段
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

3. 重写密码相关方法

AbstractBaseUser的密码操作方法默认依赖自身password字段,需重写这些方法,改为从UserCredential表操作:

from django.contrib.auth.hashers import make_password, check_password

class User(AbstractBaseUser, PermissionsMixin):
    # ... 其他代码
    
    # 获取密码
    def get_password(self):
        return self.credential.password if self.credential else ''
    
    # 设置密码(自动处理加密)
    def set_password(self, raw_password):
        if not self.credential:
            # 若未关联密码记录,自动创建
            self.credential = UserCredential.objects.create(user=self)
        self.credential.password = make_password(raw_password)
        self.credential.save()
    
    # 验证密码正确性
    def check_password(self, raw_password):
        if not self.credential:
            return False
        return check_password(raw_password, self.credential.password)

4. 调整认证后端的查询逻辑

在自定义认证后端中,获取用户时仅查询必要字段,避免Django自动添加password到查询语句:

from django.contrib.auth.backends import ModelBackend
from .models import User

class CustomAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 仅查询必要字段,同时关联密码表减少数据库查询次数
            user = User.objects.select_related('credential').only('id', 'email', 'is_active', 'is_staff').get(email=username)
            if user.check_password(password) and user.is_active:
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.select_related('credential').only('id', 'email', 'is_active', 'is_staff').get(pk=user_id)
        except User.DoesNotExist:
            return None

5. 确认配置正确性

在settings.py中确保用户模型和认证后端的配置无误:

AUTH_USER_MODEL = '你的应用名.User'
AUTHENTICATION_BACKENDS = ['你的应用名.backends.CustomAuthBackend']

完成上述修改后,重新执行数据库迁移(若已有历史迁移,需注意处理现有数据兼容性),即可正常使用request.user功能。

内容的提问来源于stack exchange,提问作者user

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:52:03