Django切换邮箱登录后出现AnonymousUser无'_meta'属性错误排查
问题原因
你遇到的问题由3个核心错误导致:
- Django默认的
authenticate身份认证方法仅接受username+password作为参数,你直接传入email参数无法被识别,因此返回None UserLoginForm表单的字段校验方法命名错误,你定义的clean_username对应的字段不存在,邮箱存在性校验逻辑完全不会触发- 你没有对
authenticate的返回结果做非空判断,直接把None传给login方法,导致系统认为当前是未登录的匿名用户,抛出'AnonymousUser' object has no attribute '_meta'错误
修复方案
方案1:无需修改认证后端,直接调整登录逻辑
修改sign_in视图代码如下:
def sign_in(request): context = {} form = UserLoginForm(request.POST or None) context['form'] = form if form.is_valid(): email = form.cleaned_data.get('email') password = form.cleaned_data.get('password') # 先根据邮箱查询对应用户 try: user_obj = User.objects.get(email__iexact=email) except User.DoesNotExist: user = None else: # 用用户名+密码走默认认证 user = authenticate(request, username=user_obj.username, password=password) # 增加非空判断再执行登录 if user is not None: login(request, user) return redirect('/') else: messages.error(request, '邮箱或密码错误') attempt = request.session.get('attempt') or 0 request.session['attempt'] = attempt + 1 else: print('test3') attempt = request.session.get('attempt') or 0 request.session['attempt'] = attempt + 1 return render(request, 'registration/sign_in.html', context)
同时修改UserLoginForm的校验方法名,把def clean_username改为def clean_email:
# 原来的clean_username改成clean_email,对应表单的email字段 def clean_email(self): email = self.cleaned_data.get("email") qs = User.objects.filter(email__iexact=email) if not qs.exists() or qs.count() != 1: raise forms.ValidationError("这是无效的用户邮箱") return email
方案2:自定义邮箱认证后端,支持直接用email参数认证
如果后续需要长期使用邮箱登录,推荐使用该方案:
- 在你的APP目录下新建
auth_backends.py,写入以下代码:
from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend class EmailAuthBackend(ModelBackend): def authenticate(self, request, email=None, password=None, **kwargs): UserModel = get_user_model() try: user = UserModel.objects.get(email__iexact=email) except UserModel.DoesNotExist: return None if user.check_password(password) and self.user_can_authenticate(user): return user return None
- 打开项目
settings.py,新增认证后端配置:
AUTHENTICATION_BACKENDS = [ # 保留默认的用户名登录能力,不需要可以删除 'django.contrib.auth.backends.ModelBackend', # 替换为你自己的APP名称路径 '你的APP名称.auth_backends.EmailAuthBackend', ]
- 按方案1的说明修改
UserLoginForm的校验方法名即可,原有sign_in视图的authenticate(email=email, password=password)逻辑可以保留正常使用。
内容的提问来源于stack exchange,提问作者darek_82
相关产品推荐
相关产品推荐

