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")