Why is checking if two passwords match in Django so complicated?

Viewed 15958

Am I doing something wrong, or is this seriously what the developers expect me to write every time I want to check if two fields are the same?

def clean(self):
    data = self.cleaned_data
    if "password1" in data and "password2" in data:
        if data["password1"] != data["password2"]:
            self._errors["password2"] = self.error_class(['Passwords do not match.'])
            del data['password2']    
    return data

And why do I have to validate that the username is unique?

def clean_username(self):
    data = self.cleaned_data['username']
    if User.objects.filter(username=data).exists():
        raise ValidationError('Username already taken.')
    return data

It's a ModelForm. It should already know there's a unique constraint?

4 Answers

Here's what I would do:

This is the only clean method you need to define to make sure 2 passwords are correct and that the username is valid.

Use the clean_fieldname method so that you don't need to do more work to validate the username.

def clean_password2(self):
    password1 = self.cleaned_data.get('password1')
    password2 = self.cleaned_data.get('password2')

    if not password2:
        raise forms.ValidationError("You must confirm your password")
    if password1 != password2:
        raise forms.ValidationError("Your passwords do not match")
    return password2

You're absolutely right, you dont need to validate the username being unique, because the ModelForm knows it needs to be unique.

The problem with your code is that you are overriding the clean() method, which means the ModelForm isn't doing its 'real' clean().

To get the default validation, call super(MyForm, self).clean() or better yet don't override clean at all and only specify clean_password2.

http://k0001.wordpress.com/2007/11/15/dual-password-field-with-django/


Edit: found out the way the admin form deals with the problem: http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/forms.py

class AdminPasswordChangeForm(forms.Form):
    """
    A form used to change the password of a user in the admin interface.
    """
    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
    password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError(_("The two password fields didn't match."))
        return password2

    def save(self, commit=True):
        """
        Saves the new password.
        """
        self.user.set_password(self.cleaned_data["password1"])
        if commit:
            self.user.save()
        return self.user
Related