Search code examples
djangodjango-formsdjango-registrationdjango-custom-user

Custom registration form. Confirm password


I used custom form for register users. I want do validation for confirm password. forms.py:

class RegistrationForm(UserCreationForm):
    '''Register for new users'''
    email = forms.EmailField(required=True)
    first_name = forms.CharField(required=True)
    last_name = forms.CharField(required=True)

    class Meta:
        model = get_user_model()
        fields = {'username', 'password1', 'password2', 'email', 'first_name', 'last_name'}

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']

        if commit:
            user.save()

        return user

template:

<div class="input-group register">
     {{ form.password.errors }}
     <label for="id_password1">Password: </label>
     {{ form.password1 }}
</div>
<div class="input-group register">
    {{ form.password.errors }}
    <label for="id_password2">Confirm password: </label>
    {{ form.password2 }}                            
</div>

views.py

def registration_view(request):
context = {}
context.update(csrf(request))
context['form'] = RegistrationForm()

if request.method == 'POST':
    form = RegistrationForm(request.POST)
    if form.is_valid():
        form.save()
        newuser = auth.authenticate(
            username=form.cleaned_data['username'],
            password=form.cleaned_data['password2']
        )
        auth.login(request, newuser)
        return redirect('home')
    else:
        context['form'] = form

return render(request, '/registration.html', context)

How can I add validation for password(also confirm password)?


Solution

  • You inherit from UserCreationForm [GitHub]. This form already does that for you.

    Indeed: the clean_password2 will validate that the two passwords are the same:

        def clean_password2(self):
            password1 = self.cleaned_data.get("password1")
            password2 = self.cleaned_data.get("password2")
            if password1 and password2 and password1 != password2:
                raise forms.ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
            return password2

    The _post_clean function will validate that the password is a valid password:

        def _post_clean(self):
            super()._post_clean()
            # Validate the password after self.instance is updated with form data
            # by super().
            password = self.cleaned_data.get('password2')
            if password:
                try:
                    password_validation.validate_password(password, self.instance)
                except forms.ValidationError as error:
                    self.add_error('password2', error)

    Finally in the save() it will use .set_password() to set the password. This is necessary, since Django's User model will, like any good user model, hash the password.

        def save(self, commit=True):
            user = super().save(commit=False)
            user.set_password(self.cleaned_data["password1"])
            if commit:
                user.save()
            return user

    You thus should not interfere with these. You here only want to add first_name and last_name. So you can add that logic with:

    class RegistrationForm(UserCreationForm):
        '''Register for new users'''
        email = forms.EmailField(required=True)
        first_name = forms.CharField(required=True)
        last_name = forms.CharField(required=True)
    
        class Meta:
            model = get_user_model()
            fields = ['username', 'email', 'first_name', 'last_name']

    That's all, since the ModelForm will take care of that.

    Note that authenticate in your view is probably not necessary, since if you construct a user, it should authenticate. You can just login here:

    def registration_view(request):
        context = {}
        context.update(csrf(request))
        if request.method == 'POST':
            form = RegistrationForm(request.POST)
            if form.is_valid():
                newuser = form.save()
                auth.login(request, newuser)
            return redirect('home')
        else:
            form = RegistrationForm()
        context['form'] = form
        return render(request, '/registration.html', context)