Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django password and password confirmation validation

Tags:

python

django

I'm having a little trouble validating two fields (password and password confirmation) in the same form.

The thing is that after validating password with a method I've created, when I try to validate password confirmation, I no longer have access to this variable, and password = self.cleaned_data['password'] is 'None'.

class NewAccountForm(forms.Form):

password =  forms.CharField(widget=forms.PasswordInput(attrs={'class': 'narrow-input', 'required': 'true' }), required=True, help_text='Password must be 8 characters minimum length (with at least 1 lower case, 1 upper case and 1 number).')
password_confirm = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'narrow-input', 'required': 'true' }), required=True, )

def __init__(self, *args, **kwargs):
    super(NewAccountForm, self).__init__(*args, **kwargs)
    self.fields['password'].label = "Password"
    self.fields['password_confirm'].label = "Password Confirmation"

"Password validation" <- this validation is working.

def clean_password(self):
    validate_password_strength(self.cleaned_data['password'])

This second validation isn't correctly performed because password = 'None':

def clean_password_confirm(self):
    password = self.cleaned_data['password']
    password_confirm = self.cleaned_data.get('password_confirm')

    print(password)
    print(password_confirm)
    if password and password_confirm:
        if password != password_confirm:
            raise forms.ValidationError("The two password fields must match.")
    return password_confirm

Is there a way to use input for field password as a variable to the second validation (clean_password_confirm) if it is already validated by the first method (clean_password)?

Thanks.

EDIT: Updated version:

def clean(self):
    cleaned_data = super(NewAccountForm, self).clean()
    password = cleaned_data.get('password')

    # check for min length
    min_length = 8
    if len(password) < min_length:
        msg = 'Password must be at least %s characters long.' %(str(min_length))
        self.add_error('password', msg)

    # check for digit
    if sum(c.isdigit() for c in password) < 1:
        msg = 'Password must contain at least 1 number.'
        self.add_error('password', msg)

    # check for uppercase letter
    if not any(c.isupper() for c in password):
        msg = 'Password must contain at least 1 uppercase letter.'
        self.add_error('password', msg)

    # check for lowercase letter
    if not any(c.islower() for c in password):
        msg = 'Password must contain at least 1 lowercase letter.'
        self.add_error('password', msg)

    password_confirm = cleaned_data.get('password_confirm')


    if password and password_confirm:
        if password != password_confirm:
            msg = "The two password fields must match."
            self.add_error('password_confirm', msg)
    return cleaned_data
like image 585
revy Avatar asked Aug 16 '16 16:08

revy


1 Answers

You can test for multiple fields in the clean() method.

Example:

def clean(self):
    cleaned_data = super(NewAccountForm, self).clean()

    password = cleaned_data.get('password')
    password_confirm = cleaned_data.get('password_confirm ')

    if password and password_confirm:
        if password != password_confirm:
            raise forms.ValidationError("The two password fields must match.")
    return cleaned_data

See the documentation on Cleaning and validating fields that depend on each other.

like image 66
SaeX Avatar answered Oct 28 '22 17:10

SaeX