Django form processing: Initialization, field access, validation and error handling.

Problem

You want to dispatch Django forms to end users and process their submitted data.

Solution

To initialize a Django form before it's dispatched to an end user, you can use the initial argument directly on a form field or as part of the form instance creation, in addition you can also use the __init__ method on a form class definition. To alter the initial layout of a form instance you can use the label_suffix argument to alter a form's label suffix (e.g.label_suffix=':'), as well as the auto_id=False argument to tell Django not to generate HTML id values on form fields.

To access form values submitted by an end user you initially use the request.POST variable to create a bound form instance (e.g.Form(request.POST)). Next, you must call the is_valid() method on the form instance to validate the submitted values against a form's data types. Immediately after calling the is_valid() method, Django creates the cleaned_data dictionary on the form instance with the fields/values that passed validation, as well as the errors dictionary with the fields/values that didn't pass validation. Equipped with a form instance with the cleaned_data & errors dictionaries, you can perform logic on the cleaned_data values or send the form back to a user to display the errors values for correction.

To perform more advanced form validation -- beyond checking form values against field data types -- you can use the validators option on form fields. In addition, you can also declare clean_<field>() methods or the clean() method on form classes to execute advanced form validation rules. All of the three previous advanced form validation techniques are also run when the is_valid() method is run.

To generate a form error in either a validators method, clean_<field>() method, the clean() method or any other part of a form's work-flow, you must raise a forms.ValidationError. All occurrences of forms.ValidationErrors are placed in a form's errors dictionary, where the key represents the related form field. If a forms.ValidationErrors is raised where it can't be determined to which field it belongs (e.g. in the clean() method) it's assigned to a special group called non-field errors. It's also possible to use a form instance's add_error() method to generate a form error, this method is helpful for cases when you want to assign error messages to a specific field and avoid them being categorized as non-field errors (e.g. add_error('field_name','error_message').

How it works

Note Ensure you know the ABCs of Django forms

This recipe assumes you already know the basics about Django forms. If concepts like form fields, unbound and bound form instances, GET/POST requests and CSRF are unfamiliar to you, I strongly recommend you first read the recipe Set up Django forms and understand their structure and workflow otherwise some of following techniques may be difficult to understand.

Because Django form processing can have a great deal of variations depending on what you want to achieve, I'll start with a bare-bones form & processing (view) method to build the discussions of the following sections. Listing 1 illustrates a sample Django form and its backing processing (view) method.

Listing 1 - Django form class with backing processing view method


from django import forms
from django.shortcuts import render

class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')  
      comment = forms.CharField(widget=forms.Textarea)

def contact(request):
    if request.method == 'POST':
        # POST, generate form with data from the request
        form = ContactForm(request.POST)
        # Reference is now a bound instance with user data sent in POST 
        # process data, insert into DB, generate email, redirect to a new URL,etc
    else:
        # GET, generate blank form
        form = ContactForm()
        # Reference is now an unbound (empty) form
    # Reference form instance (bound/unbound) is sent to template for rendering
    return render(request,'about/contact.html',{'form':form})

In listing 1 you can see we have a Django form with three form fields, as well as a backing (view) method charged with dispatching and processing the form. The dispatching sequence or GET section defines what's initially sent to a user -- in this case an empty form -- where as the processing sequence or POST section defines how to handle user submitted data -- in this case there's no logic except the assignment of user data to the form via request.POST.

Initialize forms : initial for fields & forms, __init__ method, label_suffix, auto_id and field_order

When users request a page backed by a Django form they're sent an empty form (a.k.a. unbound form) -- represented by the GET section and ContactForm() instance in listing 1. Altough the form is always empty from a user data perspective, the form can contain data from the application as part of its initialization sequence. For example, a form could be pre-filled with a user's email or name.

To perform this kind of Django form initialization you have three options. The first technique consists of initializing the form with a dictionary of values via the initial argument directly on the form instance declared in the view method. Listing 2 shows this technique.

Listing 2 - Django form instance with initial argument declared in view method


def contact(request):
        ....
        ....
    else:
        # GET, generate blank form
        form = ContactForm(initial={'email':'johndoe@coffeehouse.com','name':'John Doe'})
        # Form is now initialized for first presentation to display these values
    # Reference form instance (bound/unbound) is sent to template for rendering
    return render(request,'about/contact.html',{'form':form})

Notice in listing 2 how the ContactForm() is declared with initial={'email':'johndoe@coffeehouse.com','name':'John Doe'}. This generates a pre-filled form instance with values for the email and name fields so end users don't have to go to the trouble of typing these values from scratch themselves.

The technique in listing 2 is intended for one-time or instance specific initialization values. If you want to constantly provide a value for a given form field, a more suitable technique is to use the same initial argument directly on a form field, as illustrated in listing 3.

Listing 3 - Django form fields with initial argument


from django import forms

class ContactForm(forms.Form):
      name = forms.CharField(required=False,initial='Please provide your name')
      email = forms.EmailField(label='Your email', initial='We need your email')
      comment = forms.CharField(widget=forms.Textarea)

def contact(request):
        ....
        ....
    else:
        # GET, generate blank form
        form = ContactForm()
        # Form is now initialized for first presentation and is filled with initial values in form definition
    # Reference form instance (bound/unbound) is sent to template for rendering
    return render(request,'about/contact.html',{'form':form})

Notice in listing 3 how it's now the form fields in the form definition that are equipped with the initial argument and the form instance has no arguments. It's worth mentioning that if you use the initial argument on both the form instance and form fields, form instance values take predecence over any form field (e.g. if you combine the statements from listing 2 and listing 3, the form will always be prefilled with email='johndoe@coffeehouse.com' and name='John Doe' from listing 2).

One of the drawbacks of using the initial argument in form fields like listing 3 is that values can't change dynamically at run-time (i.e. you can't personalize the initial values based on who calls the form like listing 2). To solve this and providing the utmost flexibility for the most complex form initialization scenarios is a third technique using the __init__ method of a form class which is illustrated in listing 4.

Listing 4 - Django form initialized with __init__ method


from django import forms

class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')
      comment = forms.CharField(widget=forms.Textarea)

      def __init__(self, *args, **kwargs):
         # Get 'initial' argument if any
         initial_arguments = kwargs.get('initial', None)
         updated_initial = {}
         if initial_arguments:
            # We have initial arguments, fetch 'user' placeholder variable if any
            user = initial_arguments.get('user',None)
            # Now update the form's initial values if user
            if user:
	       updated_initial['name'] = user.first_name
               updated_initial['email'] = user.email
         # You can also initialize form fields with hardcoded values
         # or perform complex DB logic here to then perform initialization
	 updated_initial['comment'] = 'Please provide a comment'
	 # Finally update the kwargs initial reference
         kwargs.update(initial=updated_initial)
	 super(ContactForm, self).__init__(*args, **kwargs)

def contact(request):
        ....
        ....
    else:
        # GET, generate blank form
        form = ContactForm(initial={'user':request.user,'otherstuff':'otherstuff'})
        # Form is now initialized via the form's __init__ method 
    # Reference form instance (bound/unbound) is sent to template for rendering
    return render(request,'about/contact.html',{'form':form})

The first important aspect in listing 4 is how the form is initialized in the view method, notice it uses the same initial argument but the dictionary values are now {'user':request.user,'otherstuff':'otherstuff'}. Do these values look strange ? After all the form doesn't even have fields named user or otherstuff. These last values are perfectly valid and in other circumstances would be ignored because the Django form does indeed have no fields by these names, but since we'll be manipulating the guts of form initialization process in the __init__ method we can access these placeholder values for indirect initialization purposes. More importantly, using these placeholder values illustrates how it's possible to use context data or unrelated form data to initialize Django form fields.

Next let's turn our attention to the Django form's __init__ method which is inline with the form's field methods and is invoked when you create a form instance. The __init__ method's arguments *args, **kwargs are standard Python syntax, if you've never seen this last syntax check out Python basics: Methods: Default, optional, *args & **kwargs arguments.

The first step in __init__ is to check if an initial value was provided, as well as create a reference to hold the values for the initial values that will be used to initialize the form. If an initial value is present, a check is made for a user value in order to assign values for the form's actual name and email fields. Next, irrespective of any passed in values, a direct assignment is made on the form's comment field through the new reference that holds the initial value.

Finally, the form's initial reference is updated with a new set of values that reflect the form's actual fields, leading to the form's initialization using data outside the context of a form (e.g. request data, database query,etc). As a last step in the __init__ method, a call is made to the super() method so that the base/parent class initialization process takes place.

Note You should always use the initial argument or __init__ method to populate forms with initialization data and keep them unbound

It's important to note all the previous initialization techniques keep a form unbound which is a term used to describe form instances that haven't been populated with user data. The term bound is reserved for when a form's field values are populated directly with user data. This subtle difference between bound and unbound is really important when you enter the validation phase of Django forms described in the next section.

This also means the syntax ContactForm(initial={'email':'johndoe@coffeehouse.com','name':'John Doe'}) is not equivalent to ContactForm({'email':'johndoe@coffeehouse.com','name':'John Doe'}). The first variation uses the initial argument to create an unbound form instance, while the second variation creates a bound form instance by passing the values directly without any argument.

In addition to initalizing the first set of data loaded on a Django form, there are three other initialization options for Django forms that influence their layout in templates: label_suffix, auto_id and field_order.

When you generate the output for a Django form in a template -- a topic that's described in detail in the recipe Set up the layout for Django forms in templates -- form fields are most often accompanied by what's called a field label, which is another name for a human-friendly descriptor. For example, if you had fields called name and email, their default labels would be Your name and Your email, respectively. To separate field labels from a field's HTML markup (e.g. <input type="text">) Django defines a label suffix, which defaults to the : symbol to produce output that fits the pattern <field_label> : <input type="&field_type>">.

Through the label_suffix you can define a custom label suffix symbol to separate every form field from its label. So for example, the ContactForm(label_suffix='...') syntax would output every form field label separated by ... (e.g. Your email... <input type="text">). It's worth mentioning if no label_suffix.

Another initialization option for Django forms is auto_id which automatically generates an id and label for every form field on output. By default, a Django form is always set to auto_id=True so you'll always get automatically generated HTML ids and labels as illustrated in the first part of listing 5:

Listing 5 - Django form with automatic ids (default auto_id=True option) and no automatic ids auto_id=False option


<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" name="name" type="text" /></td></tr>
<tr><th><label for="id_email">Your email:</label></th><td><input id="id_email" name="email" type="email" /></td></tr>
<tr><th><label for="id_comment">Comment:</label></th><td><textarea cols="40" id="id_comment" name="comment" rows="10">
</textarea></td></tr>



<tr><th>Name:</th><td><input name="name" type="text" /></td></tr>
<tr><th>Your email:</th><td><input name="email" type="email" /></td></tr>
<tr><th>Comment:</th><td><textarea cols="40" name="comment" rows="10">\r\n</textarea></td></tr>

Notice how the field labels in the top output of listing 5 are wrapped around <label for="id_field_name"> <label> and the fields HTML tags includes the id="id_field_name" attribute. In most cases this is a desirable output as it allows fields to be easily referenced for purposes of attaching JavaScript events or CSS classes. However, for other circumstances auto_id=True can produce very verbose output and inclusively conflicting HTML tags (e.g. if you have two form instances of the same type on the same page, there will be two identical ids).

To turn off the auto generation of ids and labels you can initialze a form with the auto_id=False option. For example, the ContactForm(auto_id=False) syntax generates the output presented in the bottom half of listing 5.

Finally, another initialization option for unbound form instances that influences a form's layout is the field_order option. By default, form fields are output in the order they're declared, so the form definition in listing 1 follows the output order: name, email, comment. You can override this default field output by using the field_order option which accepts a list of field names with the desired output order. For example, the ContactForm(field_order=['email','comment','name']) syntax ensures the email field is output first, followed by comment and name. It's worth mentioning the field_order option can accept an incomplete field list, such as ContactForm(field_order=['email']) which outputs the email field followed by the remaining form fields in their declared order, in this case name and then comment. The recipe Set up the layout for Django forms in templates contains more details on field_order.

Accessing form values: request.POST and cleaned_data.

Once a user fills out a Django form, he will send the filled out form back to the server to be incorporated as part of the application (e.g. create an order, send an email, save the data to the database) -- this step is represented by the POST section in listing 1. Because the web form generation is controlled by Django and us, we instruct a user's browser to POST the form data to a given view method, in order to access the submitted form's data using Django's request.POST variable.

One of the key advantages of Django forms is you can pass the request.POST variable directly to initialize a form instance with these user provided values, as illustrated in listing 1. Although the request.POST variable is the initial access point to populate a Django form with user data, you really shouldn't use it beyond initializing a form instance, as the data in request.POST is too raw for direct access. For example, in request.POST you still don't know if the user provided data is valid. In addition, the data in request.POST is still treated as strings, so if your Django form happens to have an IntegerField() or DateField() it would need to be converted manually to the expected data type (e.g. '6' to 6 integer, '2017-01-01' to 2017-01-01 datetime), which is just unnecesary work that another another part of Django forms deals with.

Once you have a bound form generated with the request.POST variable, you can then access each of the form's field values through the cleaned_data dictionary. For example, if the bound form reference is form and the form field is named name you can use the syntax form.cleaned_data['name'] to access the form provided name value. More importantly if the form field is an IntegerField() named age the syntax form.cleaned_data['age'] produces an integer value, a formatting behavior that also applies to other form fields with non-string data types (e.g. DateField()).

Note You can't access cleaned_data until you call is_valid() on the form instance

By design it isn't possible to access a form instance's cleaned_data dictionary unless you call the is_valid() method first. If you try to cleaned_data before calling is_valid() you'll get the error AttributeError: 'form_reference' object has no attribute 'cleaned_data'.

If you think about this for a second it's really a good practice, after all why would you want to access data that hasn't been validated ? The next section describes the is_valid() method.

Validating form values : is_valid(), validators, clean_<field>() and clean()

The is_valid() method is one of the more important parts of Django form processing. Once you create a bound form generated with the request.POST variable, you call the is_valid() method on the instance to determine if the included values comply with a form's field definitions (e.g. if an EmailField() value is a valid email). Although the is_valid() method returns a boolean True or False value, it has two important side-effects:

Listing 6 illustrates the use of the is_valid() method.

Listing 6 - Django form is_valid() method for form processing


from django.http import HttpResponseRedirect

def contact(request):
    if request.method == 'POST':
        # POST, generate form with data from the request
        form = ContactForm(request.POST)
        # Reference is now a bound instance with user data sent in POST
	# Call is_valid() to validate data and create cleaned_data and errors dict
        if form.is_valid():
	   # Form data is valid, you can now access validated values in the cleaned_data dict
           # e.g. form.cleaned_data['email']
	   # process data, insert into DB, generate email
	   # Redirect to a new URL
	   return HttpResponseRedirect('/contact/thankyou')
	else:
           pass # Not needed 
           # is_valid() method already created errors dict, so form reference now contains errors 
           # this form reference is used in the final return statement where errors can then be presented accessing form.errors
    else:
        # GET, generate blank form
        form = ContactForm()
        # Reference is now an unbound (empty) form
    # Reference form instance (bound/unbound) is sent to template for rendering
    return render(request,'about/contact.html',{'form':form})

Notice in listing 6 that right after a bound form instance is created a call is made to the is_valid() method. If all the form field values comply against the form field data types, we enter a conditional where it's possible to access the form values through the cleaned_data dictionary, perform whatever business logic is necessary and relinquish control to another page, which in listing 6 is to perform redirect. If any of the form field values fails to pass a rule then is_valid() returns False and in the process creates an errors dictionary with details about the values that failed to pass their rules. Because of this last automatic creation of errors, all that's needed after is_valid returns False is to return the same form instance in order to display the errors dictionary to an end user so he can correct his mistakes.

As important as the is_valid() method is to Django form processing, its validation is just done against a form field's data type. For example, is_valid() can validate if a value is left empty, if a value matches a given number range or even if a value is a valid date, in essence anything supported by Django form field types. But what if you wanted to perform more sophisticated validation after is_valid() ? Such as checking a value against a database before deeming it valid or checking two values against one another (e.g. a provided zip code value against a provided city value). While you could add these last types of validation checks directly after the is_valid() call in the view method, Django offers three more efficient ways to enforce rules by adding them to the form field or form class definition.

If you want a reusable validation mechanism you can use across multiple Django form fields, the best choice is a validator assigned through a model field's validators option. The validators form field option expects a list of methods designed to raise a forms.ValidationError error in case a value doesn't comply with expected rules. Listing 7 illustrates a Django form with one of its fields using a custom validator method via the validators option.

Listing 7 - Django form field validators option with custom validator method for form processing

from django import forms

def validate_csv(value):
    if len(value.split(',')) == 1:
        raise forms.ValidationError(('%(value)s is not a CSV list'),
            params={'value': value},
        )


class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')
      comment = forms.CharField(widget=forms.Textarea,validators=[validate_csv])

The first section in listing 7 shows the custom validator validate_csv() method which (rudimentarly) checks if its input is a comma separated value (CSV) string (i.e. if the length of a string after splitting it with , equals 1, it means the string has no comma and therefore it's not a CSV). If the method's input is not a CSV string, Django's forms.ValidationError error is raised to indicate a rule violation. In the bottom half of listing 7 you can see a modified ContactForm where the comment field uses the validators==[validate_csv] option. This tells Django that after is_valid() is run and all the form fields have been checked for errors against their data types, it should also run the validate_csv validator method against the value provided for the comment field. If the comment value is not a CSV -- a highly hypothetical case, but just bare the example -- then a ValidatioError error is raised which is added to the same form errors dictionary from the past section used to check field values against their data types.

As you can see from the example in listing 7, you can equally reuse the custom validate_csv() method on any other form field in the same form or in another Django form through the validators option. In addition, you could also apply multiple validators to a field since the validators option accepts a list of validators. Finally, it's worth mentioning the django.core.validators package contains a series of validators you can also reuse and which are used behind by the scenes by certain form field data types.

In addition to the form field validators option, it's also possible to add complex validation form rules through the clean_<field>() and clean() methods which created as part of a Django form class -- just like __init__() described earlier. Just like methods specified in the form field validators option, clean_<field>() and clean() methods are automatically invoked when the is_valid() method is run. Listing 8 illustrates the use of two clean_<field>() methods.

Listing 8 - Django form field validation with clean_<field>() methods


from django import forms

class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')
      comment = forms.CharField(widget=forms.Textarea)

      def clean_name(self):
      	  # Get the field value from cleaned_data dict
      	  value = self.cleaned_data['name']
	  # Check if the value is all upper case
	  if value.isupper():
             # Value is all upper case, raise an error
	     raise forms.ValidationError("Please don't use all upper case later for your name, use lower case",code='uppercase')
	  # Always return value 
	  return value

      def clean_email(self):
      	  # Get the field value from cleaned_data dict
      	  value = self.cleaned_data['email']
	  # Check if the value end in @hotmail.com
	  if value.endswith('@hotmail.com'):
             # Value end in @hotmail.com, raise an error
	     raise forms.ValidationError("Please don't use a hotmail email, we simply don't like it",code='hotmail')
	  # Always return value 
	  return value

In listing 8 you can see we have two clean_<field>() methods to provide additional validation rules for the name and email fields. In every case Django automatically detects a form's field names and when it finds a method named clean_<field>() it applies it on the field value in question. This means you can have as many clean_<field>() methods as form fields.

The logic inside each clean_<field>() method follows a similar pattern. First you extract a field's value from the form's cleaned_data dictionary via the self reference which represents the form instance. Next, you run whatever rule or logic you want against the field value, if you deem the value doesn't comply you raise a forms.ValidationError which adds the error to the form instance. Finally, you must return the field value irrespective of raising an error or changing its value.

Sometimes it's necessary to apply a rule that doesn't necessarily belong to a specific field, in which case the generic clean() method is the preferred approach vs. a clean_<field>() method. Listing 9 illustrates the use of the clean() method.

Listing 9 - Django form field validation with clean() method


from django import forms

class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')
      comment = forms.CharField(widget=forms.Textarea)

      def clean(self):
      	  # Call clean() method to ensure base class validation 
      	  super(ContactForm, self).clean()

      	  # Get the field values from cleaned_data dict
	  name = self.cleaned_data.get('name',None)
	  email = self.cleaned_data.get('email',None)

	  # Check if the name is part of the email
	  if name.lower() not in email:
             # Name is not in email , raise an error
	     raise forms.ValidationError("Please provide an email that matches your name, or viceversa")


In listing 9 you can see a similar approach to the previous clean_<field>() methods in listing 8. But because the clean() method is a class wide method and you're overriding it yourself, it differs from clean_<field>() methods in that you must first call the clean() method of the base/parent form class explicitly to ensure the base class validation is applied. Form field value extraction is done identically through the cleaned_data data dictionary, as is the validation logic and the raising of forms.ValidationError to indicate a rule violation. Finally, the clean() method differs from clean_<field>() methods in that it doesn't have to return any value.

Functionally the clean() method is different because it's called after all the validators and clean_<field>() methods, a behavior that's important because all these methods rely on data from the cleaned_data dictionary. This means if a validators or clean_<field>() method raises a ValidationError error it won't return any value and the cleaned_data dictionary won't contain a value for this field. So by the time the clean() method is run the cleaned_data dictionary may not necessarily have all the form field values if one was short-circuited in a validators or clean_<field>() method, which is why the clean() method uses the safer dictionary access syntax cleaned_data.get('<field>',None).

Another important behavioral difference between the clean() method, clean_<field>() & validators methods is how they treat forms.ValidationError. When a forms.ValidationError is raised in a validators or clean_<field>() method the error is assigned to the <field> -- in the form's errors dictionary -- which is important for display purposes. But when a forms.ValidationError is raised in the clean() method the error is assigned to a special placeholder field named __all__ -- which is also placed in the form's errors dictionary.

If you want to assign an error in the clean() method to a specific form field you can use the add_error() method as illustrated in listing 10.

Listing 10 - Django form field error assignment with add_error() in clean() method


from django import forms

class ContactForm(forms.Form):
      name = forms.CharField(required=False)
      email = forms.EmailField(label='Your email')
      comment = forms.CharField(widget=forms.Textarea)

      def clean(self):
      	  # Call clean() method to ensure base class validation 
      	  super(ContactForm, self).clean()

      	  # Get the field values from cleaned_data dict
	  name = self.cleaned_data.get('name',None)
	  email = self.cleaned_data.get('email',None)

	  # Check if the name is part of the email
	  if name.lower() not in email:
             # Name is not in email , raise an error
	     message = "Please provide an email that matches your name, or viceversa"
             self.add_error('name', message)
             self.add_error('email', forms.ValidationError(message))
	     self.add_error(None, message)

Notice in listing 10 how instead of the raise forms.ValidationError() syntax we use the add_error() method on the form instance. The add_error() method accepts two arguments, the first one represents the form field name on which to assign the error and the second can be either an error messagestring or an instance of the ValidationError class.

The first two add_error() methods assign the error to the name and email fields, respectively. Where as the third add_error() method with the None key assigns the error to the special __all__ placeholder making it equivalent to the raise forms.ValidationError() syntax from listing 9.

Error form values: errors

Form errors as I described in the previous section are automatically added to a form instance in the errors dictionary after calling the is_valid() method. Inclusively, it's actually possible to access the errors dictionary directly without calling the is_valid() method, unlike the cleaned_data dictionary.

But the most important aspect of the errors dictionary is that all form errors end up in this dictionary. Whether the errors are raised because a value doesn't comply with a form field data type or with raise forms.ValidationError() in the clean() method, clean_<field>() methods, validators methods or the add_error() method in the clean() method, all errors end up in a form's errors dictionary.

The structure of the errors dictionary follows the straightforward pattern {'<field_name>':'<error_message>'} which makes it easy to identify form errors in either a view method or in a template for display purposes. The only exception to this last pattern ocurrs when a form error isn't field specific (e.g. such as those created in the clean() method) in which case a form error is assigned to a special key named __all__, errors which are also called non-field errors.

Although you can access the errors dictionary as any other Python dictionary, Django provides a series of methods described in table 1 to make working with errors much easier:

Table 1 - Django form errors methods
MethodDescription
form.errorsGives you access to the raw errors dictionary.
form.errors.as_data()Outputs a dictionary with the original ValidationError instances. For example, if errors outputs {'email':['This field is required']}, then errors.as_data() outputs {'email':[ValidationError(['This field is required'])]}.
form.errors.as_json(escape_html=False)Outputs a JSON structure with the contents of the errors dictionary. For example, if errors outputs {'email':['This field is required']}, then errors.as_json() outputs {'email':[{'message':'This field is required','code':'required'}]}. Note that by default as_json() does not escape its output, if you want errors to be escaped use the escape_html flag (e.g. as_json(escape_html=True)).
form.add_error(field,message)Associates an error message to a given form field. Although typically used in the clean() method, it can be used in a view method if necesssary. Note that if field is not specified the error message goes on to form part of the __all__ placeholder key in errors which are deemed non-field errors.
form.has_error(field, code=None)Returns a True or False value if a given field has an error. Note that by default has_error returns True if any error type is associated with a field. To perform the evaluation against a particular error type you can use the code keyword (e.g. form.has_error('email',code='required')). To check if a form has non-field errors you can use NON_FIELD_ERRORS as the field value.
form.non_field_errors()Returns a list of non-form errors associated with a form, which are errors typically created in the clean() clean method via ValidationError or add_error(None,'message').

You may have noticed the ValidationError class instances I created in all the previous examples used different arguments, which means there are really many ways to create ValidationError instances. For example, some ValidationError instances use a simple string, but it's also possible to create a ValidationError instance with a list of ValidationError instances, as well as specify a code attribute to further classify the type of error. Listing 11 illustrates a series of ValidationError class instances using these variations.

Listing 11 - Django form ValidationError instance creation


from django import forms

# Placed inside def clean_email(self):
raise forms.ValidationError("Please don't use a hotmail email, we simply don't like it",code='hotmail')

# Placed inside def clean(self):
raise forms.ValidationError([
     forms.ValidationError("Please provide an email that matches your name, or viceversa",code='custom'),
     forms.ValidationError("Please provide your professional email, %(value) doesn't look professional ",code='required',params={'value':self.cleaned_data.get('email') })

The ValidationError instance variations presented in listing 11 are all optional, but can become powerful when it comes time to display or filter error messages on a template, a process that's described in detail in the Set up the layout for Django forms in templates recipe.