I have a class-based view that subclasses 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,
})
I want to override the error message if a user's email is not yet active because they have to click a link sent to their email address. The current default message looks like this:
Instead of saying:
Please enter a correct email address and password. Note that both fields may be case-sensitive.
I want to say something to the effect of:
Please confirm your email so you can log in.
I tried:
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',
)
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,
})
The result is absolutely no effect when I try to log in with a user that does exist, but hasn't verified their email address yet.
Django uses ModelBackend
as default AUTHENTICATION_BACKENDS
and which does not authenticate the inactive users.
This is also stated in Authorization for inactive users sections,
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.
So, set AllowAllUsersModelBackend
as your AUTHENTICATION_BACKENDS
in settings.py
# settings.py
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
It doesn't affect anything other than the authentication. If we look into the source code of AllowAllUsersModelBackend
class we can see it just allowing the inactive users to authenticate.
Personally, I don't recommend this method since method-1 is the Django way of tackling this issue.
Override the clean(...)
method of PickyAuthenticationForm
class and call the AllowAllUsersModelBackend
backend as,
from django.contrib.auth.backends import AllowAllUsersModelBackend
class PickyAuthenticationForm(AuthenticationForm):
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
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',
)
Result Screenshot