edche
edche

Reputation: 678

How to put conditions in the password field?

I am creating a system with Django. I already created a login page in the beginning of the project. But now, I realized that I have no conditions for password field. I want to put some restrictions like 8 characters, uppercase and lowercase letters and numbers. How can I check this when user fills the form?

forms.py

class SignUpForm(forms.ModelForm):
    password1 = forms.CharField(max_length=250, min_length=8, widget=forms.PasswordInput)
    password2 = forms.CharField(max_length=250, min_length=8, widget=forms.PasswordInput)
...

models.py

class UserProfile(AbstractUser, UserMixin):
    ...
    last_name = models.CharField(max_length=200)
    password = models.CharField(max_length=250)

views.py

def signup(request):
    current_user = request.user
    new_user = UserProfile(company=current_user.company)
    form = SignUpForm(request.POST or None, user=request.user, instance=new_user)
    rank_list = Rank.objects.filter(company=current_user.company)

    if request.method == 'POST':
        if form.is_valid():
            form.instance.username = request.POST.get('email', None)
            new_user = form.save()
           ...

    }
    return render(request, 'signup.html', context)

EDIT

I added codes according to the answers but It did not works.

settings.py

AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    'OPTIONS': {
        'min_length': 12, }
 },
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', },
{'NAME': 'register.validators.UppercaseValidator', },
{'NAME': 'register.validators.NumberValidator', },
{'NAME': 'register.validators.LowercaseValidator', },
]

register/validators.py

import re
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _


class NumberValidator(object):
    def __init__(self, min_digits=0):
        self.min_digits = min_digits

    def validate(self, password, user=None):
        if not len(re.findall('\d', password)) >= self.min_digits:
            raise ValidationError(
                _("The password must contain at least %(min_digits)d digit(s), 0-9."),
                code='password_no_number',
                params={'min_digits': self.min_digits},
            )

    def get_help_text(self):
        return _(
            "Your password must contain at least %(min_digits)d digit(s), 0-9." % {'min_digits': self.min_digits}
        )


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


class LowercaseValidator:
    def validate(self, password, user=None):
        if not re.findall('[a-z]', password):
            raise ValidationError(
                _("The password must contain at least 1 lowercase letter, a-z."),
                code='password_no_lower',
            )

    def get_help_text(self):
        return _(
            "Your password must contain at least 1 lowercase letter, a-z."
        )

Upvotes: 2

Views: 2158

Answers (3)

edche
edche

Reputation: 678

I am edited my forms.py like this. I use my customer signup form. and this is work for me:

class SignUpForm(forms.ModelForm):
    password1 = forms.CharField(max_length=250, min_length=8, widget=forms.PasswordInput)
    password2 = forms.CharField(max_length=250, min_length=8, widget=forms.PasswordInput)

    class Meta:
        model = UserProfile
        fields = (
            'first_name', 'last_name', 'email', 'password1', 'password2', 'rank', 'image')
        labels = {
            'email': 'E-mail',
            'password1': 'Please Generate A Strong Password',
            'password2': 'Please Confirm the Password',
            'rank': 'Position'
        }

    widgets = {
        'password1': forms.PasswordInput(),
        'password2': forms.PasswordInput(),
    }

    def __init__(self, *args, **kwargs):
        # using kwargs
        user = kwargs.pop('user', None)
        super(SignUpForm, self).__init__(*args, **kwargs)
        self.fields['rank'].queryset = Rank.objects.filter(company=user.company)
        self.fields['password1'].label = 'Please Generate A Strong Password'
        self.fields['password2'].label = 'Please Confirm the Password'

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

        # 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('password1', msg)

        # check for digit
        if sum(c.isdigit() for c in password) < 1:
            msg = 'Password must contain at least 1 number.'
            self.add_error('password1', 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('password1', 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('password1', msg)

        password_confirm = cleaned_data.get('password2')

        if password and password_confirm:
            if password != password_confirm:
                msg = "The two password fields must match."
                self.add_error('password2', msg)
        return cleaned_data

Upvotes: 0

Astros
Astros

Reputation: 179

Django includes some basic validators (docs)

AUTH_PASSWORD_VALIDATORS = [
{
    'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
    'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    'OPTIONS': {
        'min_length': 9,
    }
},
{
    'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
    'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

But you can create your own validators:

In your app, create validators.py

And add your validations classes there (docs)

# EX Validation for uppercase
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."
    )

Finally update the AUTH_PASSWORD_VALIDATORS setting with the path to your validators

AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    'OPTIONS': {
        'min_length': 12, }
 },
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', },
{'NAME': 'myproject.validators.UppercaseValidator', },
]

Upvotes: 2

modo24
modo24

Reputation: 64

Check this: https://sixfeetup.com/blog/custom-password-validators-in-django

If you have more specific needs, you can create your own validators. To do so, simply create your own classes based on object and raise a ValidationError if the entered password fails.

Upvotes: 1

Related Questions