Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Form enhancements for Django (fieldset and row-attrs support, and more)
tag: 0.1.0

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.



This application provides 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.


Once installed on your Python path (see INSTALL.txt), 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``.


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'}))
            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 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

  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, 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 doctests in tests/


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_{{ }}">
      {% 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" }}
Something went wrong with that request. Please try again.