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

自定义UserModel与邮箱认证后端问题:UserModel.objects.get返回None

排查步骤与解决方法

首先明确:UserModel.objects.get(email=email) 只会在找到唯一匹配的用户时返回对象,否则会抛出 User.DoesNotExist 异常。你说它返回None,大概率是代码里用了try-except捕获了这个异常,本质还是邮箱匹配不到用户。下面是具体排查和修复方案:

1. 验证目标邮箱是否真的存在于数据库

直接通过Django shell查询,确认用户输入的邮箱是否已注册:

# 进入Django shell
python manage.py shell
# 导入你的自定义用户模型
from yourapp.models import UserModel
# 查询目标邮箱(替换成实际输入的邮箱)
UserModel.objects.filter(email="test@example.com").exists()
  • 如果返回False:
    • 要么是该邮箱未注册,要么是输入的邮箱与数据库存储有大小写/格式差异(比如库里是Test@Example.com,用户输入test@example.com)。
    • 解决:注册和认证时统一邮箱格式为小写
      # models.py 中重写save方法统一处理
      class UserModel(AbstractBaseUser):
          # ...其他字段
          def save(self, *args, **kwargs):
              self.email = self.email.lower()
              super().save(*args, **kwargs)
      
      # authentication.py 中认证时也转小写
      user = UserModel.objects.get(email=email.lower())
      

2. 检查自定义UserModel的邮箱字段配置

确保邮箱字段设置了unique=True,且已正确迁移:

# models.py 正确示例
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("Email must be set")
        email = self.normalize_email(email)  # 用Django自带方法格式化邮箱
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

class UserModel(AbstractBaseUser):
    email = models.EmailField(verbose_name="邮箱", unique=True)
    is_active = models.BooleanField(default=True)
    # ...其他必填字段(如is_staff、username等)

    objects = UserManager()

    USERNAME_FIELD = "email"  # 核心:指定用邮箱作为登录标识
    REQUIRED_FIELDS = []
  • 迁移检查:执行python manage.py makemigrations和python manage.py migrate,确保数据库表结构同步。

3. 确认认证后端的实现与配置

认证后端代码(authentication.py)

推荐用get_user_model()获取自定义模型,避免硬编码:

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth import get_user_model

class EmailBackend(BaseBackend):
    def authenticate(self, request, email=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=email.lower())
            if user.check_password(password):
                return user
        except UserModel.DoesNotExist:
            return None  # 找不到用户返回None,触发登录失败重定向

    def get_user(self, user_id):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None

Settings.py 配置

必须指定自定义用户模型,并将后端加入认证列表:

# settings.py
AUTH_USER_MODEL = "yourapp.UserModel"  # 替换成你的app名和模型名
AUTHENTICATION_BACKENDS = [
    "yourapp.authentication.EmailBackend",
    # 可选:保留默认用户名认证
    "django.contrib.auth.backends.ModelBackend",
]

4. 检查登录视图的参数传递

确保登录视图正确传递email参数到认证后端:

# views.py 自定义登录视图示例
from django.contrib.auth import authenticate, login
from django.shortcuts import render, redirect

def login_view(request):
    if request.method == "POST":
        email = request.POST.get("email")
        password = request.POST.get("password")
        user = authenticate(request, email=email, password=password)
        if user:
            login(request, user)
            return redirect("home")
        else:
            return render(request, "login.html", {"error": "邮箱或密码错误"})
    return render(request, "login.html")
  • 前端表单的name属性必须是email:
<form method="post">
    {% csrf_token %}
    <input type="email" name="email" placeholder="请输入邮箱">
    <input type="password" name="password" placeholder="请输入密码">
    <button type="submit">登录</button>
</form>

5. 排查中间件/信号干扰

暂时禁用非必要的中间件,或者检查是否有信号在用户保存时修改了邮箱字段,导致存储的邮箱与用户输入不一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:17:04