Django add custom form errors to form.errors

ZedsWhatSheSaid picture ZedsWhatSheSaid · Oct 20, 2015 · Viewed 10.2k times · Source

I want to write a form for registering a user. I want to implement a password match where the user has to type in his password twice. This is my current form:

from django import forms
from passwords.fields import PasswordField

class AccountForm(forms.Form):
    email = forms.EmailField(max_length=255)
    username = forms.CharField(max_length=40)
    password = PasswordField(label="Password")
    password_confirm = PasswordField(label="Password")

In my view I want to check for validations, and if something is not valid I want to print the specific error in my template. This is the current state of my views:

def signup(request):
    if request.method == 'POST':
        form = AccountForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            password_confirm = form.cleaned_data['password_confirm']

            if password != password_confirm:
                print("Password don't match")

            #Account.objects.create_user(email, password, username = username)

        else:
            print(form.errors)
            form = Account()
    return render(request, 'authentication/auth.html', {'signup': form})

Now my aim is to deliver the form errors to the template. I check for example the match of the password with the password_confirm variable. If they don't match I want that to be visible in the template. Do you guys know how I can add my custom form errors / validations to my form and display these errors in my template?

Answer

karthikr picture karthikr · Oct 20, 2015

For this, you need to use the clean method.

class AccountForm(forms.Form):
    email = forms.EmailField(max_length=255)
    username = forms.CharField(max_length=40)
    password = PasswordField(label="Password")
    password_confirm = PasswordField(label="Password")

    def clean(self):
        cd = self.cleaned_data
        if cd.get('password') != cd.get('password_confirm'):
            self.add_error('password_confirm', "passwords do not match !")
        return cd

Now, when form.is_valid() is called from your view, the form's clean method is called implicitly and this validation is executed.

Read on this: clean values that depend on each other for more info.

Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special “field” (called all), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you need to call add_error().

Also, note that .add_error was introduced in django 1.7.

If you are using django 1.6 or below, you would do:

if cd.get('password') != cd.get('password_confirm'):
    self._errors["password_confirm"] = self.error_class(["Passwords do not match"])
    del cleaned_data["password_confirm"]