Django has everything you need to do server-side validation, but it’s also a good idea to do client-side validation. Here’s how you can integrate the jQuery Validation plugin with your Django Forms.
jQuery Validation Rules
jQuery validation works by assigning validation rules to each element in your form. These rules can be assigned a couple different ways:
- Class Rules
- Metadata Rules
- Rules Object
Django Form Class Rules
The simplest validation rules, such as required, can be assigned as classes on your form elements. To do this in Django, you can specify custom widget attributes.
from django import forms
from django.forms import widgets
class MyForm(forms.Form):
title = forms.CharField(required=True, widget=widgets.TextInput(attrs={
'class': 'required'
}))
In Django 1.2, there’s support for a required css class, but you can still use the technique above to specify other validation rules.
Django Form Metadata Rules
For validation methods that require arguments, such minlength and maxlength, you can create metadata in the class attribute. You’ll have to include the jQuery metadata plugin for this style of rules.
from django import forms
from django.forms import widgets
class MyForm(forms.Form):
title = forms.CharField(required=True, minlength=2, maxlength=100, widget=widgets.TextInput(attrs={
'class': '{required:true, minlength:2, maxlength:100}'
}))
jQuery Validate Rules Object
If your validation requirements are more complex, or you don’t want to use the metadata plugin or class based rules, you can create a rules object to pass as an option to the validate method. This object can be generated in your template like so:
<script type="text/javascript">
FORM_RULES = {
'{{ form.title.name }}': 'required'
};
$(document).ready(function() {
$('form').validate({
rules: FORM_RULES
});
});
</script>
The reason I suggest generating the rules object in your template is to avoid hardcoding the field name in your javascript. A rules object can also be used in conjunction with class and metadata rules, so you could have some rules assigned in individual element classes or metadata, and other rules in your rules object.
Error Messages
If you want to keep the client-side validation error messages consistent with Django’s validation error messages, you’ll need to copy Django’s error messages and specify them in the metadata or in a messages object.
Metadata Messages
Messages must be specified per-field, and per-rule. Here’s an example where I specify the minlength
message for the title
field.
from django import forms
from django.forms import widgets
class MyForm(forms.Form):
title = forms.CharField(minlength=2, widget=widgets.TextInput(attrs={
'class': '{minlength:2, messages:{minlength:"Ensure this value has at least 2 characters"}}'
}))
Messages Object
Messages can also be specified in javascript object, like so:
<script type="text/javascript">
FORM_RULES = {
'{{ form.title.name }}': 'required'
};
FORM_MESSAGES = {
'{{ form.title.name }}': 'This field is required'
};
$(document).ready(function() {
$('form').validate({
rules: FORM_RULES,
messages: FORM_MESSAGES
});
});
</script>
Just like with validation rules, messages in element metadata can be used in conjunction with a global messages object. Note: if an element has a title attribute, then the title will be used as the default error message, unless you specify ignoreTitle:
false
in the jQuery validate options.
Error Labels vs Errorlist
Django’s default error output is an error list, while the default for jQuery Validation errors is a label with class="error"
. So in order to unify your validation errors, there’s 2 options:
- make jQuery Validation output an error list
- output error labels instead of an error list in the template
Personally, I prefer the simple error labels produced by jQuery validation. To make Django generate those instead of an error list, you can do the following in your templates:
{{ field }}
{% if field.errors %}
{# NOTE: must use id_NAME for jquery.validation to overwrite error label #}
<label class='error' for='id_{{ field.name }}' generated="true">{{ field.errors|join:". " }}</label>
{% endif %}
You could also create your own error_class for outputting the error labels, but then you’d lose the ability to specify the for attribute.
If you want to try to make jQuery validation produce an error list, that’s a bit harder. You can specify a combination of jQuery validation options and get a list, but there’s not an obvious way to get the errorlist
class on the ul
.
$('form').validate({
errorElement: 'li',
wrapper: 'ul'
});
Other options you can look into are errorLabelContainer, errorContainer
, and a highlight
function.
Final Recommendations
I find it’s easiest to specify class and metadata rules in custom widget attributes 90% of the time, and use a rules object only when absolutely necessary. For example, if I want to require only the first elements in a formset, but not the rest, then I may use a rules object in addition to class and metadata rules. For error messages, I generally use a field template like the above example that I include for each field:
{% with form.title as field %}{% include "field.html" %}{% endwith %}
Or if the form is really simple, I do
{% for field in form %}{% include "field.html" %}{% endfor %}
Like this:
Like Loading...