27

Here I need to add an extra confirmation password in my form.I used Django's modelform. I also need to validate both passwords. It must raise a validation error if password1 != password2.

Here is my forms.py:

class UserForm(forms.ModelForm):
    password=forms.CharField(widget=forms.PasswordInput())

    class Meta:
        model=User
        fields=('username','email','password')

class UserProfileForm(forms.ModelForm):
    YESNO_CHOICES = (('male', 'male'), ('female', 'female'))
    sex = forms.TypedChoiceField(choices=YESNO_CHOICES, widget=forms.RadioSelect)
    FAVORITE_COLORS_CHOICES=(('red','red'),('blue','blue'))
    favorite_colors = forms.MultipleChoiceField(required=False,widget=forms.CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)
    dob = forms.DateField(widget=forms.DateInput(format = '%d/%m/%Y'), 
                                 input_formats=('%d/%m/%Y',))

    class Meta:

        model=UserProfile
        fields=('phone','picture','sex','favorite_colors','dob')

And here is my registration function:

def register(request):
    registered = False
    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        profile_form = UserProfileForm(data=request.POST)



        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save(commit=False)
            user.set_password(user.password)
            user.save()
            profile = profile_form.save(commit=False)
            profile.user = user
            if 'picture' in request.FILES:
                profile.picture = request.FILES['picture']
            profile.save()
            registered = True
        else:
            print user_form.errors, profile_form.errors
    else:
        user_form = UserForm()
        profile_form = UserProfileForm()

    return render(request,
            'mysite/register.html',
            {'user_form': user_form, 'profile_form': profile_form, 'registered': registered} )
user2226755
  • 12,494
  • 5
  • 50
  • 73
sunnysm
  • 339
  • 2
  • 5
  • 11

5 Answers5

37

Use clean like

class UserForm(forms.ModelForm):
    password=forms.CharField(widget=forms.PasswordInput())
    confirm_password=forms.CharField(widget=forms.PasswordInput())
    class Meta:
        model=User
        fields=('username','email','password')

    def clean(self):
        cleaned_data = super(UserForm, self).clean()
        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")

        if password != confirm_password:
            raise forms.ValidationError(
                "password and confirm_password does not match"
            )
Sahand
  • 7,980
  • 23
  • 69
  • 137
itzMEonTV
  • 19,851
  • 4
  • 39
  • 49
15
def clean(self):
    cleaned_data = super(UserAccountForm, self).clean()
    password = cleaned_data.get("password")
    confirm_password = cleaned_data.get("confirm_password")

    if password != confirm_password:
        self.add_error('confirm_password', "Password does not match")

    return cleaned_data
  • 1
    Thanks! `add_error()`is much better than `raise forms.ValidationError` so you can display all errors instead of only showing the first error – NaturalBornCamper Sep 09 '20 at 02:01
2

Try this for forms.py:

class UserForm(forms.Form):
    password = forms.CharField(widget=forms.PasswordInput())
    password_confirm = forms.CharField(widget=forms.PasswordInput())

    class Meta:
        model = User
        fields=('username','email','password')

And this in views.py:

if user_form.is_valid() and profile_form.is_valid() and user_form.cleaned_data['password'] == user_form.cleaned_data['password_confirm']:
    ...
elif user_form.data['password'] != user_form.data['password_confirm']:
    user_form.add_error('password_confirm', 'The passwords do not match')
Kevin
  • 597
  • 4
  • 14
1

You can have a look at how Django does it for UserCreationForm.

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

Here password2 refers to the confirm_password field, under the assumption that it appears after the password field. Trying to use the same implementation for clean_password may lead to an error that the confirm_password data wasn't found.

This has the advantage that you're raising the error for a particular Field, instead of the whole form, which you can then render appropriately in your template.

However, if you're trying to validate data across multiple fields, the documentation advises overriding the clean() method, as answered by Savai.

The source code is available here.

Kartik
  • 53
  • 8
0

Confirm password is already available in UserCreationForm

class UserRegistrationForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("username", "email", "password1", "password2")

This will automatically verify password1==password2 when form.is_valid() is called.

Here I am only taking email as a separate form arguments for further clean up and validation

Rajat Tyagi
  • 320
  • 5
  • 9