Skip to content


django-validation: an introduction

Some time ago I wrote this generic AJAX Django form validation code. Some people didn’t like this, as AJAX should not be used to perform form validation, which is sometimes true, sometimes not, as I pointed out before.

So I’ve been thinking since some time to create a Django templatetag which allows one to generate client-side Javascript form validation code without writing any code himself (unless using custom widgets). Today I got into it.

The resulting project is called django-validation. It basicly allows one to write a Newforms form class, and generate client-side validation code for this form in a template. Currently only CharField validation is implemented, more should follow soon and is easy to add.

Next to validation of built-in field types, one can also add code to validate custom fields. This can be done inside an inner class of the field class.

The current release is very alpha-grade software, a lot of enhancements could be done, and most certainly more standard field type validators should be written. Next to this, field type inheritance isn’t supported for now (so if your field type A inherits CharField, no CharField validation will be done), this should change soon.

Patches are, obviously, very welcome!

Here’s a sample how to use it. First we define a very basic form:

class TestForm(forms.Form):
    first_name = forms.CharField(max_length=128)
    test = TestField(required_value=u'I like django-validation')

This form uses a custom class (just for demonstration purposes). This class only performs client-side validation, no clean() function is provided, although in real field types this should obviously be added. More information can be found in the inline comments:

from validation.templatetags.validation import add_error
class TestField(forms.CharField):
    def __init__(self, *args, **kwargs):
        if not 'required_value' in kwargs.keys():
            raise Exception, 'required_value should be provided'
        self.required_value = kwargs['required_value']
        del kwargs['required_value']
        super(TestField, self).__init__(*args, **kwargs)

    class ClientValidator:
        '''
        This inner class knows how to generate Javascript validation code for this field type.
        The code will be pasted inside a function block. There is at least one assigned variable, 'field',
        which is the DOM element we got to validate.

        More parameters can be defined in the 'parameters' attribute. These parameters will be added
        to the Javascript function prototype, and the value of the form field parameter value will be
        assigned.

        We need to define the field class name, so the django-validation code can generate suitable
        function names.
        '''
        parameters = ('required_value', )
        field_class = 'TestField'

        def render(self, output):
            '''
            The render function should output Javascript code to check the value of the 'field' element.
            It is called inside a Javascript function scope.

            output is a StringIO object. Normally only write or writelines calls should be used.
            '''
            output.write('value = field.value;\n')
            output.write('if(value != required_value) {\n')
            # This error message should be internationalized.
            # See the add_error documentation.
            add_error(output, 'error_msg', 'Field value should be %(value)d.', (('%(value)d', 'required_value'), ))
            output.write('    return [error_msg];\n')
            output.write('}\n')

Finally, here’s how to use it inside a template (this must be one of the worse HTML/Javascript snippets I ever wrote):

{% load validation %}
<html>
<body>
    <form>
        {{ form.as_p }}
        <p><input type="submit" onclick="return testform(this.form);" />
    </form>
    <div id="errors"></div>
    {% validation_js form 'validate_testform' %}
    <script type="text/javascript">
        function testform(form) {
            valid = true;
            errors = validate_testform(form);
            err = "<ul>";
            for(field in errors) {
                if(errors[field] != null) {
                    err += '<li>' + field + ': ' + errors[field][0] + '</li>';
                    valid = false;
                }
            }
            err += '</ul>';
            if(valid)
                err = 'Form is valid';
            document.getElementById('errors').innerHTML = err;
            return false;
        }
    </script>
</body>
</html>

The current code is available in a git repository. Enjoy!

Posted in Development.

Tagged with , , , , , , , .


6 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Kurt McKee says

    I think the second code block needs another newline.

  2. Nicolas says

    Kurt: I might be overlooking something, but… where exactly?

  3. Kurt McKee says

    The first line, where it says “add_errorclass”.

  4. Nicolas says

    Fixed, thanks!

  5. sc says

    good job

    in my project here is error
    from validation.templatetags.validation import add_error
    ImportError: No module named validation.templatetags.validation

    thanks

Continuing the Discussion

  1. django python | Rahul's Work linked to this post on October 5, 2012

    [...] http://eikke.com/django-validation-an-introduction/ [...]



Some HTML is OK

or, reply to this post via trackback.