Skip to main content
Added a try/catch to avoid server errors when a non-existent email is used.
Source Link

Here is one way to do it so that both username and email are accepted:

from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.forms import ValidationError class EmailAuthenticationForm(AuthenticationForm): def clean_username(self): username = self.data['username'] if '@' in username:   try:  username = User.objects.get(email=username).username except ObjectDoesNotExist: raise ValidationError(  self.error_messages['invalid_login'], code='invalid_login',  params={'username':self.username_field.verbose_name}, ) return username 

Don't know if there is some setting to set the default Authentication form but you can also override the url in urls.py

url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'), 

Raising the ValidationError will prevent 500 errors when an invalid email is submitted. Using the super's definition for "invalid_login" keeps the error message ambiguous (vs a specific "no user by that email found") which would be required to prevent leaking whether an email address is signed up for an account on your service. If that information is not secure in your architecture it might be friendlier to have a more informative error message.

Here is one way to do it so that both username and email are accepted:

from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User class EmailAuthenticationForm(AuthenticationForm): def clean_username(self): username = self.data['username'] if '@' in username: username = User.objects.get(email=username).username return username 

Don't know if there is some setting to set the default Authentication form but you can also override the url in urls.py

url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'), 

Here is one way to do it so that both username and email are accepted:

from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.forms import ValidationError class EmailAuthenticationForm(AuthenticationForm): def clean_username(self): username = self.data['username'] if '@' in username:   try:  username = User.objects.get(email=username).username except ObjectDoesNotExist: raise ValidationError(  self.error_messages['invalid_login'], code='invalid_login',  params={'username':self.username_field.verbose_name}, ) return username 

Don't know if there is some setting to set the default Authentication form but you can also override the url in urls.py

url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'), 

Raising the ValidationError will prevent 500 errors when an invalid email is submitted. Using the super's definition for "invalid_login" keeps the error message ambiguous (vs a specific "no user by that email found") which would be required to prevent leaking whether an email address is signed up for an account on your service. If that information is not secure in your architecture it might be friendlier to have a more informative error message.

Source Link
Juho Rutila
  • 2.5k
  • 1
  • 28
  • 48

Here is one way to do it so that both username and email are accepted:

from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User class EmailAuthenticationForm(AuthenticationForm): def clean_username(self): username = self.data['username'] if '@' in username: username = User.objects.get(email=username).username return username 

Don't know if there is some setting to set the default Authentication form but you can also override the url in urls.py

url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),