Easier Django form rendering with formtags
26 helmi 2013 • Teknologia ja digitaalinen kehitys
Here at Sofokus, we’ve benefited greatly from Open Source software and feel it is time to start giving something back. We present Sofokus Formtags library: a template tag library for Django that makes generating customized form HTML easy.
Get it from our GitHub page.
So, what can the Sofokus formtags library do for you? Let’s take a look at an example. Our sample Django form definition looks like this:
[gist id=”fb180a935f5323c6644c”]
If the standard {{ form }}
output is not good enough, the usual way to generate customized HTML is something like this:
[gist id=”f1ff6c309c6b2f95e410″]
For brevity, I’ve omitted the actual field markup. As the field code often needs to be reused, it’s a good idea to put it into a separate template for easy inclusion or, even better, use a macro library.
Easy grouping
Now, what if we want to use fieldsets or otherwise group fields together visually? The regular {% for %}
tag is no longer adequate and repeating a macro or include call for each field is not very DRY. What if you change the form and forget to update the template? Or what if you want to make generic templates to use with many different forms that share common structure? This is where our new tags come in.
The {% form %}
tag selects the form we are working on. The {% field %}
tag is like a smarter {% for %}
tag that only iterates through the fields that match the specified criteria.
Notice how the first {% field %}
doesn’t have any arguments? That is the ”catchall” matcher that grabs every available field. In this example, the catchall matcher also appears before the ”favorite_*
” matcher, yet it leaves out the fields starting with ”favorite_”. This is because more specific matchers have precedence over more general ones. The ”favorite_*
” matcher has higher precedence than the catchall (which has the lowest of all matchers) and gets first pickings at the form.
Thanks to the catchall field, no field goes forgotten. When not used, left over fields will raise an exception, alerting you to the problem immediately.
Behind the scenes, field reordering is made possible by rendering the entire form twice. The output of the first pass is discarded, but the order of the field matchers is remembered. The matchers are then sorted in order of their precedence and the form fields assigned. Doing the rendering in two passes, instead of inspecting the static structure of the template, enables forms to be constructed dynamically.
Hidden fields
The formtags library contains other helpful tools besides tags for grouping and rearranging fields. If your form has hidden fields, you typically need to include something like this:
[gist id=”f3099cc11e55f9005092″]
Formtags has this packaged into a single convenient tag:
[gist id=”bbfb6aa91288d186717f”]
Choices, choices
Sometimes you need a non-standard choice field, but writing a custom widget for a oneshot would be overkill. When that happens, try the {% field_choices %}
tag.
The {% field_choices %}
is a looping tag that wraps together commonly needed choice item properties, such as the label, value and whether or not the option is selected. The tag’s items come directly from the enclosing field, so it must be nested in a {% field %}
tag.
Widget specific rendering
The formtags library has one more feature to help you write field rendering templates. Often, you have a simple form that doesn’t need any special field specific rendering, but could use special field type specific rendering. For example, you might want to have your standard input fields inline and text area fields on a separate paragraph.
This is a job for the widget_name
filter. For example:
[gist id=”c5b808ba6613a2733070″]
This renders textareas and radio choice fields differently from other fields.
The widget_name
filter normally returns the class name of the field’s widget. As this filter is commonly used in a conditional like in the above example, it accepts a list of names as an argument as a convenience:
[gist id=”4af3e804b33e09883cec”]
If the widget’s name matches any of the listed names, the filter returns True
and False
otherwise.
Summary
The formtags tag library contains four new tags and one filter for Django’s templating engine. The new tags simplify grouping fields in a DRY manner, rendering customized choice fields and creating reusable custom field rendering templates.
The library is freely available under the MIT license at our GitHub page. Full documentation of all features is included in the library’s docstrings, so be sure to take a peek!