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

Django邮箱+用户名登录报错:'AnonymousUser' object has no attribute '_meta'

解决Django邮箱+用户名双登录中的AnonymousUser错误

问题重现

在Django项目中实现邮箱/用户名双登录功能,已在settings.py配置自定义认证后端AuthenticationEmailBackend和默认ModelBackend,但使用邮箱登录时触发错误:'AnonymousUser' object has no attribute '_meta',用户名登录正常。

相关配置与代码如下:

settings.py 配置

AUTHENTICATION_BACKENDS = (
    "accounts.auth.AuthenticationEmailBackend",
    "django.contrib.auth.backends.ModelBackend",
)

原视图代码

def login_view(request):
    if request.method == 'POST':
            email =request.POST['username']
            password = request.POST['password']
            user = authenticate(username=email, password=password)
            print(user)
            #if user is not None:
            login(request,user,backend="accounts.auth.AuthenticationEmailBackend")
            return redirect('/')
    else:
        pass
    return render(request,'accounts/login.html')

原自定义认证后端代码

class AuthenticationEmailBackend(object):
    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)
        except UserModel.DoesNotExist:
            return None
        else:
            if user.check_password(password):
                return user
        return None

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

错误原因

  1. 跳过用户有效性判断:视图中注释掉了if user is not None:逻辑,当authenticate返回None(邮箱不存在或密码错误)时仍执行login,此时传入的user为None,login会创建AnonymousUser对象,但该对象不具备用户模型的_meta属性,触发报错。
  2. 硬编码依赖User模型:自定义后端的get_user方法直接使用User.objects.get(),若项目使用自定义用户模型会引发查找错误,不符合Django最佳实践。
  3. 强制指定后端冗余:login时手动指定后端,忽略了authenticate返回用户自带的_backend标识,可能导致认证上下文不匹配。

修复方案

1. 恢复用户非空验证逻辑

执行login前必须判断user是否有效,避免传入None。

2. 修正自定义后端的get_user方法

使用get_user_model()动态获取用户模型,兼容默认及自定义用户模型场景。

3. 移除login时的手动后端指定(可选)

authenticate会自动遍历配置的后端,返回验证通过的用户并绑定对应后端标识,无需手动指定。

修正后的完整代码

修正后的视图代码

def login_view(request):
    if request.method == 'POST':
        input_value = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=input_value, password=password)
        if user is not None:
            login(request, user)
            return redirect('/')
        # 可添加登录失败提示逻辑
    return render(request,'accounts/login.html')

修正后的自定义认证后端代码

from django.contrib.auth import get_user_model

class AuthenticationEmailBackend(object):
    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)
        except UserModel.DoesNotExist:
            return None
        if user.check_password(password):
            return user
        return None

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

注:若希望自定义后端仅处理邮箱登录,保留上述authenticate逻辑即可,默认ModelBackend会自动处理用户名登录,配置的后端列表会按顺序依次验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 10:35:29