Reputation: 73
I have an existing django views.py where I have some password, username, and email validation logic applied. However, going forward I need to apply more advanced password validation. for e.g. password length limitation, uppercase sesitivity etc. I have a code written for advanced validation, but I am not able to apply them on my existing views.py. Below is the code from views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib import messages
from . import validator
def register(request):
if request.method == 'POST':
first_name = request.POST['first_name']
last_name = request.POST['last_name']
email = request.POST['email']
username = request.POST['username']
password = request.POST['password', validator.MinimumLengthValidator]
password2 = request.POST['password2']
# check if the password match
if password == password2:
if User.objects.filter(username=username).exists():
messages.error(request, 'username already exist')
return redirect('register')
else:
if User.objects.filter(email=email).exists():
messages.error(request, 'Registration Failed - Try different email address')
return redirect('register')
else:
user = User.objects.create_user(username=username, password=password, email=email,
first_name=first_name, last_name=last_name)
user.save()
messages.success(request, 'Registration complete, please proceed to login')
return redirect('register')
else:
messages.error(request, 'password dose not match')
return redirect('register')
else:
return render(request, 'ACCOUNTS/register.html')
Below is the code for advanced password validation from validate.py
import re
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
class MinimumLengthValidator:
def __init__(self, min_length=8):
self.min_length = min_length
def validate(self, password, user=None):
if len(password) < self.min_length:
raise ValidationError(
_("This password must contain at least %(min_length)d characters."),
code='password_too_short',
params={'min_length': self.min_length},
)
def get_help_text(self):
return _(
"Your password must contain at least %(self.min_length)d characters."
% {'min_length': self.min_length}
)
class NumberValidator(object):
def validate(self, password, user=None):
if not re.findall('\d', password):
raise ValidationError(
_("The password must contain at least %(min_digits)d digit(s), 0-9."),
code='password_no_number',
)
def get_help_text(self):
return _(
"Your password must contain at least 1 digit, 0-9."
)
class UppercaseValidator(object):
def validate(self, password, user=None):
if not re.findall('[A-Z]', password):
raise ValidationError(
_("The password must contain at least 1 uppercase letter, A-Z."),
code='password_no_upper',
)
def get_help_text(self):
return _(
"Your password must contain at least 1 uppercase letter, A-Z."
)
I have tried below steps.
I imported the validator.py in the views.py,and tried to call the module.function inside the password field as below
password = request.POST['password', validator.MinimumLengthValidator]
But that doesn't work. If I am right, I can write a mixin class and call it in my views.py. But I am using function based views. So, I am not sure if I can use mixin. Please suggest how can we achieve the desired result.
ValidationError at /accounts/register/
['The password must contain at least 1 uppercase letter, A-Z.']
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/register/
Django Version: 2.1.5
Exception Type: ValidationError
Exception Value:
['The password must contain at least 1 uppercase letter, A-Z.']
Exception Location: /root/PycharmProjects/interview/ACCOUNTS/validator.py in validate, line 45
Python Executable: /root/PycharmProjects/myvenv/bin/python
Python Version: 3.6.7
Python Path:
['/root/PycharmProjects/interview',
'/usr/lib/python36.zip',
'/usr/lib/python3.6',
'/usr/lib/python3.6/lib-dynload',
'/root/PycharmProjects/myvenv/lib/python3.6/site-packages']
Server time: Wed, 6 Feb 2019 07:15:39 +0000
Upvotes: 3
Views: 4078
Reputation: 51998
You need to use forms to use those validators cleanly. Although you need to change those as well.
def min_length(password): # validator
if not re.findall('\d', password):
raise ValidationError(
_("The password must contain at least %(min_digits)d digit(s), 0-9."),
code='password_no_number',
)
Then update the form:
# in forms
class UserForm(forms.Form):
password = forms.CharField(widget=forms.PasswordInput(),validators=[min_length])
But, if don't want to use django forms, then you need to run those validation manually, for example:
def register(request):
validators = [MinimumLengthValidator, NumberValidator, UppercaseValidator]
if request.method == 'POST':
# some code
password = request.POST('password')
try:
for validator in validators:
validator().validate(password)
except ValidationError as e:
messages.error(request, str(e))
return redirect('register')
Upvotes: 3