Form enhancements for Django (fieldset and row-attrs support, and more)
Switch branches/tags
Pull request Compare This branch is 4 commits ahead, 88 commits behind carljm:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



This application provides utilities for enhancing Django's form handling:

  1. BetterForm and BetterModelForm classes, which are subclasses of django.forms.Form and django.forms.ModelForm, respectively. BetterForm and BetterModelForm allow subdivision of forms into fieldsets which are iterable from a template, and also allow definition of row_attrs which can be accessed from the template to apply attributes to the surrounding container (<li>, <tr>, or whatever) of a specific form field.
  2. A ClearableFileField to enhance FileField and ImageField with a checkbox for clearing the contents of the field.
  3. An ImageWidget which display a thumbnail of the image rather than just the filename.


Install from PyPI with easy_install or pip:

pip install django-form-utils

or get the in-development version:

pip install django-form-utils==dev

To use django-form-utils in your Django project, just include form_utils in your INSTALLED_APPS setting. django-form-utils does not provide any models, but including it in INSTALLED_APPS makes the form_utils template tag library available.

You may also want to override the default form rendering templates by providing alternate templates at templates/form_utils/better_form.html and templates/form_utils/form.html.


django-form-utils requires Django 1.0 or later.

ClearableFileField requires Django 1.1 or later.

ImageWidget requires the Python Imaging Library. sorl-thumbnail is optional, but without it full-size images will be displayed instead of thumbnails.


Simply inherit your form class from form_utils.forms.BetterForm (rather than django.forms.Form), or your modelform class from form_utils.forms.BetterModelForm, and define the fieldsets and/or row_attrs attributes of the inner Meta class:

class MyForm(BetterForm):
    one = forms.CharField()
    two = forms.CharField()
    three = forms.CharField()
    class Meta:
        fieldsets = (('main', {'fields': ('two',), 'legend': ''}),
                     ('Advanced', {'fields': ('three', 'one'),
                                   'description': 'advanced stuff',
                                   'classes': ('advanced', 'collapse'}))
        row_attrs = {'one': {'style': 'display: none'}}


Fieldset definitions are similar to ModelAdmin fieldset definitions: each fieldset is a two-tuple with a name and an options dictionary. Valid fieldset options in the dictionary include:

(required) A tuple of field names to display in this fieldset.
A tuple/list of extra CSS classes to apply to the fieldset.
This value, if present, will be the contents of a legend tag to open the fieldset. If not present the name of the fieldset will be used (so a value of '' for legend must be used if no legend is desired.)
A string of optional extra text to be displayed under the legend of the fieldset.

When iterated over, the fieldsets attribute of a BetterForm (or BetterModelForm) yields Fieldset s. Each Fieldset has a name attribute, a legend attribute, a classes attribute (the classes tuple collapsed into a space-separated string), and a description attribute, and when iterated over yields its BoundField s.

For backwards compatibility, a BetterForm or BetterModelForm can still be iterated over directly to yield all of its BoundField s, regardless of fieldsets.

For more detailed examples, see the tests in tests/


The row_attrs declaration is a dictionary mapping field names to dictionaries of attribute/value pairs. The attribute/value dictionaries will be flattened into HTML-style attribute/values (i.e. {'style': 'display: none'} will become style="display: none"), and will be available as the row_attrs attribute of the BoundField.

Also, a CSS class of "required" or "optional" will automatically be added to the row_attrs of each BoundField, depending on whether the field is required.


A possible template for rendering a BetterForm:

{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
{% for fieldset in form.fieldsets %}
  <fieldset class="{{ fieldset.classes }}">
  {% if fieldset.legend %}
    <legend>{{ fieldset.legend }}</legend>
  {% endif %}
  {% if fieldset.description %}
    <p class="description">{{ fieldset.description }}</p>
  {% endif %}
  {% for field in fieldset %}
    {% if field.is_hidden %}
      {{ field }}
    {% else %}
      <li{{ field.row_attrs }}>
        {{ field.errors }}
        {{ field.label_tag }}
        {{ field }}
    {% endif %}
  {% endfor %}
{% endfor %}

django-form-utils also provides a convenience template filter, render. It is used like this:

{{ form|render }}

By default, it will check whether the form is a BetterForm, and if so render it using the template form_utils/better_form.html. If not, it will render it using the template form_utils/form.html. (In either case, the form object will be passed to the render template's context as form).

The render filter also accepts an optional argument, which is a template name or comma-separated list of template names to use for rendering the form:

{{ form|render:"my_form_stuff/custom_form_template.html" }}

Fields and Widgets


A replacement for django.forms.FileField that has a checkbox to clear the field of an existing file. Use as you would any other form field class:

from django import forms

from form_utils.fields import ClearableFileField

class MyModelForm(forms.ModelForm):
    pdf = ClearableFileField()

ClearableFileField also accepts two keyword arguments, file_field and template.

file_field is the instantiated field to actually use for representing the file portion. For instance, if you want to use ClearableFileField to replace an ImageField, and you want to use ImageWidget, you could do the following:

from django import forms

from form_utils.fields import ClearableFileField
from form_utils.widgets import ImageWidget

class MyModelForm(forms.ModelForm):
    avatar = ClearableFileField(

By default, file_field is a plain forms.FileField with the default forms.FileInput widget.

template is a string defining how the FileField (or alternative file_field) and the clear checkbox are displayed in relation to each other. The template string should contain variable interpolation markers %(input)s and %(checkbox)s. The default value is %(input)s Clear: %(checkbox)s.

To use ClearableFileField in the admin; just inherit your admin options class from form_utils.admin.ClearableFileFieldsAdmin instead of django.contrib.admin.ModelAdmin, and all FileField``s and ``ImageField``s in that model will automatically be made clearable (while still using the same file/image field/widget they would have otherwise, including any overrides you provide in ``formfield_overrides).


form_utils.fields.ClearableImageField is just a ClearableFileField with the default file field set to forms.ImageField rather than forms.FileField.


A widget for representing an ImageField that includes a thumbnail of the current image in the field, not just the name of the file. (Thumbnails only available if sorl-thumbnail is installed; otherwise the full-size image is displayed). To use, just pass in as the widget class for an ImageField:

from django import forms

from form_utils.widgets import ImageWidget

class MyForm(forms.Form):
    pic = forms.ImageField(widget=ImageWidget())

ImageWidget accepts a keyword argument, template. This is a string defining how the image thumbnail and the file input widget are rendered relative to each other. The template string should contain variable interpolation markers %(input)s and %(image)s. The default value is %(input)s<br />%(image)s. For example, to display the image above the input rather than below:

pic = forms.ImageField(
    widget=ImageWidget(template='%(image)s<br />%(input)s'))

To use in the admin, set as the default widget for ImageField using formfield_overrides:

from django.db import models

from form_utils.widgets import ImageWidget

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = { models.ImageField: {'widget': ImageWidget}}