For this project I won’t be using Django’s built-in user authentication application. It’s a bit restrictive for my taste (but getting better in Django 1.5 from what I can tell).
One common use case is to validate the user’s username and password when logging in. Rather than place this logic within the view, it’s cleaner to override the default is_valid method with some additional logic that checks the password.
Here’s an example form with a username and password field. The username field allows either a username or email address, and I’m using Django’s built-in password hasher.
forms/signin.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django import forms | |
from app.models import User | |
from django.contrib.auth.hashers import check_password | |
from django.db.models import Q | |
class SignInForm(forms.Form): | |
username = forms.CharField(max_length=User._meta.get_field('email').max_length) | |
password = forms.CharField(min_length=6, max_length=16, widget=forms.PasswordInput()) | |
go = forms.CharField(required=False, max_length=50, widget=forms.HiddenInput()) | |
def is_valid(self): | |
# run the parent validation first | |
valid = super(SignInForm, self).is_valid() | |
# we're done now if not valid | |
if not valid: | |
return valid | |
# so far so good, get this user based on the username or email | |
try: | |
user = User.objects.get( | |
Q(username=self.cleaned_data['username']) | Q(email=self.cleaned_data['username']) | |
) | |
# no user with this username or email address | |
except User.DoesNotExist: | |
self._errors['no_user'] = 'User does not exist' | |
return False | |
# verify the passwords match | |
if not check_password(self.cleaned_data['password'], user.password): | |
self._errors['invalid_password'] = 'Password is invalid' | |
return False | |
# all good | |
return True |
You can then simply use form.is_valid() in your view:
views/signin.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if form.is_valid(): | |
# … logic to login the user … | |
# redirect to a protected page | |
return HttpResponseRedirect(reverse('account')) |
How do you display the errors in the template?
using ” {{ form.errors }} ” causes it to display errors like this “invalid_passwordPassword is invalid”
You can display the errors for a specific field like this:
You can optionally use striptags to remove any Django formatting:
Thanks. works perfect!!!
Thanks 🙂 Worked like a charm
Your post helped me a bunch, thanks! And the new way to properly inject a custom error message on a field is using self.add_error(field_name, error_message)
http://stackoverflow.com/questions/5083493/is-valid-vs-clean-django-forms/40416585#40416585
Never use self._errors but instead self.add_error, like self.add_error(’email’, ‘Email is already in use’).