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

