Django自定义AuthenticationForm传LoginView出现多余输入框问题
问题原因
django.contrib.auth.forms.AuthenticationForm 本身是继承自基础Form类的普通表单,不是ModelForm,所以你在子类里写的class Meta配置(包括model、fields属性)不会生效。
这个父类默认硬编码了username字段作为登录标识字段,你在子类里额外新增email字段后,表单实例一共会包含username、email、password三个字段,模板循环渲染时自然会多出一个输入框。
修复步骤
1. 修正表单代码
首先移除父类自带的username字段,同时重写表单校验逻辑,把输入的邮箱作为认证参数传给认证系统,替换默认的用户名校验逻辑:
from django.contrib.auth.forms import AuthenticationForm from django import forms from django.contrib.auth import authenticate class AccountSignInForm(AuthenticationForm): # 移除父类默认的username字段 username = None email = forms.EmailField( widget=forms.EmailInput(attrs={'placeholder': 'E-Mail..'}), label='E-Mail' ) password = forms.CharField( widget=forms.PasswordInput(attrs={'placeholder': 'Password..'}), label='Password' ) def clean(self): email = self.cleaned_data.get('email') password = self.cleaned_data.get('password') if email and password: # 把邮箱作为认证用户名参数传入 self.user_cache = authenticate( self.request, username=email, password=password ) if self.user_cache is None: raise self.get_invalid_login_error() self.confirm_login_allowed(self.user_cache) return self.cleaned_data
2. 配置邮箱认证逻辑(如果未配置)
如果你的Account自定义用户模型没有将USERNAME_FIELD设置为email,需要额外新增邮箱认证后端,否则表单提交时会找不到对应用户:
- 新建
accounts/backends.py文件:
from django.contrib.auth import get_user_model from django.contrib.auth.backends import ModelBackend class EmailAuthBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): User = get_user_model() try: user = User.objects.get(email=username) except User.DoesNotExist: return None if user.check_password(password) and self.user_can_authenticate(user): return user return None
- 在项目
settings.py中注册认证后端:
AUTHENTICATION_BACKENDS = [ 'accounts.backends.EmailAuthBackend', 'django.contrib.auth.backends.ModelBackend', ]
3. 修正视图层配置
你原有代码里的success_url直接传字符串'HomePageView'无法正常解析跳转,需要用reverse_lazy指向对应命名路由:
from django.contrib.auth.views import LoginView from django.urls import reverse_lazy from .forms import AccountSignInForm class AccountLoginView(LoginView): template_name = 'accounts/login.html' form_class = AccountSignInForm # 替换为你自己首页的路由命名 success_url = reverse_lazy('home')
4. 模板无需修改
原有模板循环渲染表单字段的逻辑会自动过滤掉被置为None的username字段,最终页面只会保留E-Mail、Password两个输入框。
内容的提问来源于stack exchange,提问作者AMWST313
相关产品推荐
相关产品推荐

