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

DRF认证在单元测试数据库中失效问题排查

问题分析与解决方案

核心原因

测试环境中authenticate(username=email, password=password)返回None,但check_password验证通过、生产环境正常,大概率和以下几点相关:

1. 自定义User模型的USERNAME_FIELD配置错误

Django的authenticate函数默认使用AUTH_USER_MODEL中USERNAME_FIELD指定的字段作为username参数的匹配字段。如果你的自定义User模型未将USERNAME_FIELD设置为email,那么authenticate(username=email, ...)会去匹配username字段而非email字段——即使邮箱正确,只要username字段不等于邮箱,就会返回None。

检查你的User模型代码,确认是否有如下配置:

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    # 其他字段...
    
    USERNAME_FIELD = 'email'  # 必须设置这一行,让Django用邮箱作为登录标识
    REQUIRED_FIELDS = []  # 根据需求调整

2. 测试用例中用户创建的密码处理问题

虽然check_password验证通过,但仍需确认BaseTestCase中创建user_1时,是否正确使用set_password方法设置密码(而非直接赋值明文):

# 正确创建方式1
self.user_1 = User.objects.create_user(
    email='test@example.com',
    password='12345678'
)

# 正确创建方式2
self.user_1 = User(email='test@example.com')
self.user_1.set_password('12345678')
self.user_1.save()

如果直接赋值self.user_1.password = '12345678',密码不会被加密,authenticate会因密码不匹配返回None(你的情况check_password为True,这条可能性较低,但仍需确认)。

3. 认证后端配置问题

确认settings.py中配置了正确的认证后端,确保支持邮箱登录:

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    # 若有自定义后端,需确保它支持通过邮箱认证
]

默认的ModelBackend会使用USERNAME_FIELD指定的字段进行认证,只要USERNAME_FIELD设置正确,默认后端即可正常工作。

排查步骤

  1. 优先检查自定义User模型的USERNAME_FIELD是否设置为email,这是最可能的原因;
  2. 确认测试用例中创建用户时,密码是通过create_user或set_password加密后保存的;
  3. 在测试用例中添加调试代码,验证用户字段匹配情况:
    print("user_1 username:", self.user_1.username)
    print("user_1 email:", self.user_1.email)
    
    如果两者不一致,说明USERNAME_FIELD配置错误,导致authenticate找错了字段。

修复示例

若为USERNAME_FIELD未设置的问题,修改自定义User模型:

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.db import models

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('用户必须提供邮箱')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(verbose_name='邮箱', unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []
    
    objects = UserManager()

重新运行测试后,authenticate应该能正确找到用户并返回实例。

内容的提问来源于stack exchange,提问作者Selman Faruk Yılmaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 01:37:45