Django comes with some great modules for form handling. You can have forms generated from models, create your own form classes, build form-sets, and plenty of other goodness. However, it doesn't have everything. Some of the widgets aren't the richest, form sequences can be difficult to create, logic can often end up spread out across multiple form objects for more complex forms, and your presentation is spread through templates and form objects.
We recently had a project come up where we needed all the form handling and presentation to be easily encapsulated into one central spot. We required that sequences, and sequences of sequences be supported. Additionally, we needed to develop these forms quickly and have the same rich validation functionality of the Django form module.
We looked high and low for a solution, and found a lot of lows. Then when we had a look at what the folks over at the Pylons project were doing and came across Deform: a kick-ass Python HTML form generation library. It is easy to understand and use, it includes a wide variety of widgets, has great error handling and validation support, and you can centralize all your code in one spot.
Check out this example from the docs(http://deformdemo.repoze.org/). This all the code required to create a form representing a sequence of sequences widgets:
Now, before we continue, a little primer. Deform heavily depends on the Colander library (also part of Pylons). Colander is a system for validating and deserializing data obtained via XML, JSON, an HTML form post or any other equally simple data serialization. Deform uses it to handle validation and schemas. So make sure you have the Colander docs open whenever you have the Deform docs open. This article is about integrating Deform into Django. Please see the Deform documentation for how to use Deform.
Great huh? Looks like we found just we needed, and the components of the Pylons project are loosely coupled, so we can drop it in and start using it right away:
However, there seems to be one little problem: Deform does not work in Django.
The Pylons project handles parsing of POST data a little differently then Django. Deform marks up generated forms with special hidden fields to delineate where sequence data begins, ends, and what order it is in. It also reuses these fields names. The problem is Django parses submitted forms into QueryDicts, and dicts don't preserve the order and the reused hidden field names. For Deform to be able to read the data, it needs to be in the form of a an ordered list of tuples representing the name and value pairs of the submitted form elements. This is a big problem. Luckily, after some searching we were able find simple workaround using standard off the shelf python libraries. We simply use the parse_qsl() function from the urlparse module. The best part is it returns the parsed form data exactly the way Deform needs it:
We also need to make sure we change the form enctype in our HTML. The parse_qsl() function cannot parse multipart/form-data. Sorry folks, this means no file upload.
That's it folks, you can now use Deform in your Django projects. Here is a full example of all the code required to integrate Deform into Django.
First the Python code:
Now the template:
All the documentation you need can be found here:
Thanks goes out to the good folks at Pylons for their great work.