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

自定义AuthenticationForm登录不存在账户时触发AnonymousUser无_meta属性错误

Django自定义AuthenticationForm登录不存在账户触发AttributeError问题解决

问题现象

使用自定义AuthenticationForm登录不存在的账户时,触发如下错误:

File "C:\python\CTFp\.venv\Lib\site-packages\django\utils\functional.py", line 253, in inner
    return func(_wrapped, *args)
           ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'AnonymousUser' object has no attribute '_meta'

登录已存在的账户时无此错误,切换为基础AuthenticationForm后错误消失。

相关代码

forms.py

class AuthenticationForm(BaseAuthenticationForm):

    def clean(self):
        username = self.cleaned_data.get("username")
        password = self.cleaned_data.get("password")
        ogg = User.objects.filter(Q(email=username) or Q(username=username)).first()

        if ogg is not None and password:
            self.user_cache = authenticate(
                self.request, username=ogg.username, password=password
            )
            if self.user_cache is None:
                raise self.get_invalid_login_error()
            else:
                self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data

urls.py

urlpatterns = [path('signin', views.LoginView.as_view(authentication_form=forms.AuthenticationForm),
         {'template_name': 'users/signin.html'},
         name='signin'),]

models.py

class User(AbstractUser):
    challenges = models.ManyToManyField(Challenge)

问题原因

  1. 逻辑漏洞:当登录的账户不存在时(ogg为None),自定义clean方法未设置self.user_cache,此时Django默认将其设为AnonymousUser。而LoginView后续处理会尝试访问用户模型的_meta属性,AnonymousUser并非Django数据库模型,没有该属性,从而触发错误。
  2. 查询条件错误:原代码中使用Q(email=username) or Q(username=username)是错误的,Python逻辑运算符or会将Q对象转换为布尔值,导致实际查询条件失效,可能引发意外的用户匹配结果。

解决方案

修改自定义AuthenticationForm的clean方法,完善验证逻辑并修正查询条件:

class AuthenticationForm(BaseAuthenticationForm):

    def clean(self):
        username = self.cleaned_data.get("username")
        password = self.cleaned_data.get("password")

        if username and password:
            # 使用Django查询位运算符|同时匹配邮箱和用户名
            user = User.objects.filter(
                Q(email=username) | Q(username=username)
            ).first()
            
            if not user:
                # 用户不存在时直接抛出登录错误
                raise self.get_invalid_login_error()
            
            self.user_cache = authenticate(
                self.request, username=user.username, password=password
            )
            
            if self.user_cache is None:
                raise self.get_invalid_login_error()
            else:
                self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data

关键修改说明

  • 先校验username和password均存在,再执行后续逻辑
  • 用户不存在时立即抛出登录错误,避免user_cache处于未初始化状态
  • 将查询条件中的or替换为Django查询专用的|,确保多条件匹配逻辑正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:51:19