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

