Django form field validation and auth password val

2019-08-17 04:55发布

I'm using Django 1.10.6 and working on a registration form. On a forms.py I want to use the min_length argument for the password form field to help prevent unnecessary server requests, because Django adds that attribute to the CSS and most browsers will check that before allowing a form to be submitted.

However, Django doesn't seem to like when I use form field validation along with AUTH_PASSWORD_VALIDATORS in certain cases. When I open up inspector on the registration page and delete the CSS for the min_length attribute of the password input (thus preventing being prompted by my browser to enter more characters) and submit the request with less than 8 characters, the form field validation fails and Django deletes/empties (sorry, not sure of the correct term) the cleaned data so the password is None, which then causes the rest of the AUTH_PASSWORD_VALIDATORS to throw errors. This is the error which results object of type 'NoneType' has no len()

Here's my registration class on forms.py

class RegisterForm(forms.Form):
    username = forms.CharField(label="Username", max_length=30,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'username'}))
    email = forms.CharField(label="Email", max_length=254,
                            widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'email'}))
    # when I remove the min_length here it works,
    # however I would like to have the benefit of the input's min_length being checked by the browser first
    password = forms.CharField(label="Password", min_length=8,
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'password', 'type' : 'password'}))
    repassword = forms.CharField(label="Re-Enter Password",
                               widget=forms.TextInput(attrs={'class': 'form-control', 'name': 'repassword', 'type' : 'password'}))

    def clean(self):
        cleaned_data = super(RegisterForm, self).clean()
        password1 = cleaned_data.get('password')
        password2 = cleaned_data.get('repassword')

        #validate that the two passwords match each other
        if password1 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")

        # when the following 2 lines are uncommented
        # and I remove the min_length validator via inspector
        # and enter a password shorter than 8, password1 is None 
        # print(password1)
        # import pdb;pdb.set_trace()

        validators = passwordValidation.get_default_password_validators()
        passwordValidation.validate_password(password1,User,validators)    

Here are the validators found in settings.py

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        # I've tried this commented and uncommented, same results either way
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': { 'min_length' : 8 }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },

]

Is there a way that I can still have the client side min_length validation that the form field provides along with using the validate_password method?

Edit - Forgot to add that I can bypass this by individually calling each class found in django.contrib.auth.password_validation, but it seems like this is one of those situations where there's a standard way to do it but I'm not aware of it. For example...

from django.contrib.auth.password_validation import CommonPasswordValidator
...
if CommonPasswordValidator().validate(password1):
    raise forms.ValidationError("Please choose another password")

0条回答
登录 后发表回答