使用自定义 AuthenticationForm 覆盖 Django LoginView 错误消息
Override Django LoginView Error Message With Custom AuthenticationForm
我有一个基于 class 的观点认为 class 是 LoginView
.
from django.contrib.auth.views import LoginView
class CustomLoginView(LoginView):
def get_success_url(self):
url = self.get_redirect_url()
return url or reverse_lazy('knowledgebase:user_home', kwargs={
'username':self.request.user.username,
})
如果用户的电子邮件尚未激活,我想覆盖错误消息,因为他们必须单击发送到他们电子邮件地址的 link。当前的默认消息如下所示:
而不是说:
Please enter a correct email address and password. Note that both
fields may be case-sensitive.
我想说的大意是:
Please confirm your email so you can log in.
我试过了:
accounts/forms.py
from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import gettext as _
class PickyAuthenticationForm(AuthenticationForm):
def confirm_login_allowed(self, user):
if not user.is_active:
raise forms.ValidationError(
_("Please confirm your email so you can log in."),
code='inactive',
)
accounts/views.py
class CustomLoginView(LoginView): # 1. <--- note: this is a class-based view
form_class = PickyAuthenticationForm # 2. <--- note: define form here?
def get_success_url(self):
url = self.get_redirect_url()
return url or reverse_lazy('knowledgebase:user_home', kwargs={
'username':self.request.user.username,
})
当我尝试使用 确实 存在但尚未验证其电子邮件地址的用户登录时,结果绝对无效。
您需要使用AllowAllUsersModelBackend
在这里您将获得设置自定义后端的说明
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-authentication-backends
希望对您有所帮助。
当我只想覆盖消息时,我不相信设置自定义后端是解决方案。我通过定义 form_invalid
进行了临时修复。是的,它很老套,但就目前而言,它可以解决问题。怀疑这对任何人都有帮助,但发现 form.errors
很有趣。也许有人可以以此为基础来解决他们的具体问题。
def form_invalid(self, form):
"""If the form is invalid, render the invalid form."""
#TODO: This is EXTREMELY HACKY!
if form.errors:
email = form.cleaned_data.get('username')
if User.objects.filter(email=email, username=None).exists():
if len(form.errors['__all__']) == 1:
form.errors['__all__'][0] = 'Please confirm your email to log in.'
return self.render_to_response(self.get_context_data(form=form))
方法 - 1
Django 使用 ModelBackend
as default AUTHENTICATION_BACKENDS
并且不对非活动用户进行身份验证。
Authorization for inactive users 部分中也有说明,
An inactive user is one that has its is_active
field set to False
. The
ModelBackend
and RemoteUserBackend
authentication backends prohibits
these users from authenticating. If a custom user model doesn’t have
an is_active
field, all users will be allowed to authenticate.
所以,在settings.py
[=32=中将AllowAllUsersModelBackend
设为你的AUTHENTICATION_BACKENDS
]
# settings.py
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
它对我的 Django 应用有多大影响?
除了身份验证,它不会影响任何其他内容。如果我们查看 source code of AllowAllUsersModelBackend
class,我们可以看到它只允许 inactive 用户进行身份验证。
方法 - 2
我个人不推荐这种方法,因为 method-1 是 Django 解决这个问题的方法。
覆盖PickyAuthenticationForm
class的clean(...)
方法并调用AllowAllUsersModelBackend
后端为,
from django.contrib.auth.backends import AllowAllUsersModelBackend
class PickyAuthenticationForm(AuthenticationForm):
<b>def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username is not None and password:
backend = AllowAllUsersModelBackend()
self.user_cache = backend.authenticate(self.request, username=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</b>
def confirm_login_allowed(self, user):
if not user.is_active:
raise forms.ValidationError(
"Please confirm your email so you can log in.",
code='inactive',
)
结果截图
我有一个基于 class 的观点认为 class 是 LoginView
.
from django.contrib.auth.views import LoginView
class CustomLoginView(LoginView):
def get_success_url(self):
url = self.get_redirect_url()
return url or reverse_lazy('knowledgebase:user_home', kwargs={
'username':self.request.user.username,
})
如果用户的电子邮件尚未激活,我想覆盖错误消息,因为他们必须单击发送到他们电子邮件地址的 link。当前的默认消息如下所示:
而不是说:
Please enter a correct email address and password. Note that both fields may be case-sensitive.
我想说的大意是:
Please confirm your email so you can log in.
我试过了:
accounts/forms.py
from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import gettext as _
class PickyAuthenticationForm(AuthenticationForm):
def confirm_login_allowed(self, user):
if not user.is_active:
raise forms.ValidationError(
_("Please confirm your email so you can log in."),
code='inactive',
)
accounts/views.py
class CustomLoginView(LoginView): # 1. <--- note: this is a class-based view
form_class = PickyAuthenticationForm # 2. <--- note: define form here?
def get_success_url(self):
url = self.get_redirect_url()
return url or reverse_lazy('knowledgebase:user_home', kwargs={
'username':self.request.user.username,
})
当我尝试使用 确实 存在但尚未验证其电子邮件地址的用户登录时,结果绝对无效。
您需要使用AllowAllUsersModelBackend
在这里您将获得设置自定义后端的说明
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#specifying-authentication-backends
希望对您有所帮助。
当我只想覆盖消息时,我不相信设置自定义后端是解决方案。我通过定义 form_invalid
进行了临时修复。是的,它很老套,但就目前而言,它可以解决问题。怀疑这对任何人都有帮助,但发现 form.errors
很有趣。也许有人可以以此为基础来解决他们的具体问题。
def form_invalid(self, form):
"""If the form is invalid, render the invalid form."""
#TODO: This is EXTREMELY HACKY!
if form.errors:
email = form.cleaned_data.get('username')
if User.objects.filter(email=email, username=None).exists():
if len(form.errors['__all__']) == 1:
form.errors['__all__'][0] = 'Please confirm your email to log in.'
return self.render_to_response(self.get_context_data(form=form))
方法 - 1
Django 使用 ModelBackend
as default AUTHENTICATION_BACKENDS
并且不对非活动用户进行身份验证。
Authorization for inactive users 部分中也有说明,
An inactive user is one that has its
is_active
field set toFalse
. TheModelBackend
andRemoteUserBackend
authentication backends prohibits these users from authenticating. If a custom user model doesn’t have anis_active
field, all users will be allowed to authenticate.
所以,在settings.py
[=32=中将AllowAllUsersModelBackend
设为你的AUTHENTICATION_BACKENDS
]
# settings.py
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
它对我的 Django 应用有多大影响?
除了身份验证,它不会影响任何其他内容。如果我们查看 source code of AllowAllUsersModelBackend
class,我们可以看到它只允许 inactive 用户进行身份验证。
方法 - 2
我个人不推荐这种方法,因为 method-1 是 Django 解决这个问题的方法。
覆盖PickyAuthenticationForm
class的clean(...)
方法并调用AllowAllUsersModelBackend
后端为,
from django.contrib.auth.backends import AllowAllUsersModelBackend
class PickyAuthenticationForm(AuthenticationForm):
<b>def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username is not None and password:
backend = AllowAllUsersModelBackend()
self.user_cache = backend.authenticate(self.request, username=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</b>
def confirm_login_allowed(self, user):
if not user.is_active:
raise forms.ValidationError(
"Please confirm your email so you can log in.",
code='inactive',
)
结果截图