reg: How to use Django Password validation in my existing views?

319 views
Skip to first unread message

Amitesh Sahay

unread,
Feb 6, 2019, 1:18:38 AM2/6/19
to Django Users

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 sensitivity etc. I have a code written for advanced validation, but I am not able to apply them to 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.

Regards,

Amitesh Sahay
91-750 797 8619

Amitesh Sahay

unread,
Feb 6, 2019, 2:24:31 AM2/6/19
to Django Users
Anyway, I have found the answer to my own question. Below is the modified views.py code.

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


Regards,
Amitesh Sahay
91-750 797 8619

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/894430447.3071951.1549433756290%40mail.yahoo.com.
For more options, visit https://groups.google.com/d/optout.

Mike Dewhirst

unread,
Feb 6, 2019, 2:33:42 AM2/6/19
to 'Amitesh Sahay' via Django users
On 6/02/2019 5:15 pm, 'Amitesh Sahay' via Django users wrote:
>
> 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 sensitivity etc. I have a code written
> for advanced validation, but I am not able to apply them to my
> existing views.py.
>

You appear to be avoiding Django forms. Conventional wisdom says the
best reason for using forms is to employ the built-in validation like
this ...

from django.contrib.auth.forms import UserCreationForm

class MyUserCreationForm(UserCreationForm):
    """
https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#
    custom-users-and-the-built-in-auth-forms
    """
    first_name = forms.CharField(
        max_length=30,
        required=True,
        help_text='Required',
    )
    last_name = forms.CharField(
        max_length=30,
        required=True,
        help_text='Required'
    )
    username = forms.CharField(
        max_length=150,
        required=True,
        help_text='Required. Letters, digits and @/./+/-/_ only',
    )
    email = forms.EmailField(
        max_length=254,
        required=True,
        help_text='Required'
    )
    class Meta(UserCreationForm.Meta):
        model = User
        fields = [
            'first_name',
            'last_name',
            'username',
            'password1',
            'password2',
            'email',
        ]

    def __init__(self, *args, **kwargs):
        super(CommonUserCreationForm, self).__init__(*args, **kwargs)
        if 'first_name' in self.fields:
self.fields['first_name'].widget.attrs.update({'autofocus': True})


If you do that you can simplify your register_view() like this ...


from django.contrib.auth import get_user_model
from .forms import CommonUserCreationForm

def register_view(request):
    if request.method == 'POST':
        form = MyUserCreationForm(request.POST)

        # don't like usernames which differ only by character case
        #
        username = form.data.get('username')
        User = get_user_model()
        try:
            user = User.objects.get(username__iexact=username)
            i_username = user.username
            if i_username.lower() == username.lower():
                form.add_error(
                    'username',
                    ValidationError('{0} already
exists'.format(i_username))
                )
        except User.DoesNotExist:
            # DoesNotExist is the expected case
            pass
        #

        if form.is_valid():
            form.save()
            user = User.objects.get(username__iexact=username)
            user.username = form.cleaned_data.get('username')
            user.first_name = form.cleaned_data.get('first_name')
            user.last_name = form.cleaned_data.get('last_name')
            user.email = form.cleaned_data.get('email')
            user.save()
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=username, password=raw_password)
            auth_login(request, user)
            return redirect('myapp:index_view')
    else:
        form = MyUserCreationForm()
    return render(request, 'register.html', {'form': form})


And finally to answer your original question if you do something similar
to the above you can add password validators *to be used in the form* in
your settings module. Like this ...


#
https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME':
'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME':
'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'error_message': 'Password too short',
            'help_message': 'This password needs to be at least 23
characters',
        }
    },
    {
        'NAME':
'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME':
'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
    {
        'NAME':
'pwned_passwords_django.validators.PwnedPasswordsValidator',
        'OPTIONS': {
            'error_message': 'Known insecure password',
            'help_message': 'That is a known insecure password and
cannot be used here.',
        }
    },
]

Hope that helps

Mike
> =||||User||.objects.create_user(username=username,||||password=password,||||email=email,|
> |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.
>
> Regards,
>
> Amitesh Sahay
> *91-750 797 8619*
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com
> <mailto:django-users...@googlegroups.com>.
> To post to this group, send email to django...@googlegroups.com
> <mailto:django...@googlegroups.com>.
> <https://groups.google.com/d/msgid/django-users/894430447.3071951.1549433756290%40mail.yahoo.com?utm_medium=email&utm_source=footer>.

Mike Dewhirst

unread,
Feb 6, 2019, 6:47:11 PM2/6/19
to django...@googlegroups.com
from .forms import MyUserCreationForm    # sorry
> # from .forms import CommonUserCreationForm
Reply all
Reply to author
Forward
0 new messages