Django newbie here.
I wrote simplified login form which takes email and password. It works great if both email and password are supplied, but if either is missing i get KeyError exception. According to django documentation this should never happen:
By default, each Field class assumes the value is required, so if you pass an empty value -- either None or the empty string ("") -- then clean() will raise a ValidationError exception
I tried to write my own validators for fields (clean_email and clean_password), but it doesn't work (ie I get KeyError exception). What am I doing wrong?
class LoginForm(forms.Form):
email = forms.EmailField(label=_(u'Your email'))
password = forms.CharField(widget=forms.PasswordInput, label=_(u'Password'))
def clean_email(self):
data = self.cleaned_data['email']
if not data:
raise forms.ValidationError(_("Please enter email"))
return data
def clean_password(self):
data = self.cleaned_data['password']
if not data:
raise forms.ValidationError(_("Please enter your password"))
return data
def clean(self):
try:
username = User.objects.get(email__iexact=self.cleaned_data['email']).username
except User.DoesNotExist:
raise forms.ValidationError(_("No such email registered"))
password = self.cleaned_data['password']
self.user = auth.authenticate(username=username, password=password)
if self.user is None or not self.user.is_active:
raise forms.ValidationError(_("Email or password is incorrect"))
return self.cleaned_data
from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) # Redirect to a success page. ... else: # Return an 'invalid ...
Django comes with an excellent built-in User model and authentication support. It is a primary reason most developers prefer Django over the Flask, FastAPI, AIOHttp, and many other frameworks.
You could leverage Django's built-in way to override how Authentication happens by setting AUTHENTICATION_BACKENDS in your settings.py
Here's my EmailAuthBackend:
#settings.py
AUTHENTICATION_BACKENDS = (
'auth_backend.auth_email_backend.EmailBackend',
'django.contrib.auth.backends.ModelBackend',
)
#auth_email_backend.py
from django.contrib.auth.backends import ModelBackend
from django.forms.fields import email_re
from django.contrib.auth.models import User
class EmailBackend(ModelBackend):
"""
Authenticate against django.contrib.auth.models.User
"""
def authenticate(self, **credentials):
return 'username' in credentials and \
self.authenticate_by_username_or_email(**credentials)
def authenticate_by_username_or_email(self, username=None, password=None):
try:
user = User.objects.get(email=username)
except User.DoesNotExist:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
user = None
if user:
return user if user.check_password(password) else None
else:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
#forms.py
#replaces the normal username CharField with an EmailField
from django import forms
from django.contrib.auth.forms import AuthenticationForm
class LoginForm(AuthenticationForm):
username = forms.EmailField(max_length=75, label='Email')
next = forms.CharField(widget=forms.HiddenInput)
Hope that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With