8. Fieldsets

In HTML the <form>-element is just a data-abstraction layer. It has no display properties and is not intended to be styled or annotated. Its purpose is to group one or more input fields, in order to submit their gathered input data to the server altogether.

On the other side, we might want to visually group those input fields and optionally add a legend tag to create a caption for the form. We also might want to group related input fields visually by surrounding them with a border. For this purpose the HTML standard defines the <fieldset> tag. Django itself does not offer any abstraction for this HTML tag. If one wants to use it, this has to be done on the template level when rendering the form.

To fill this gap, django-formset introduces a Python class to handle the <fieldset>-element. From a technical point of view, a fieldset behaves exactly like a single form and in HTML it always must be wrapped inside a <form>-element. If we want to use more than one fieldset, then we have to group them using Form Collections, just as we would do with normal forms.

Another purpose of using fieldsets, appart from adding a border and legend to a form, is to use Conditional Field and Fieldset Expressions. This allows us to hide or disable the whole fieldset depending on the context of other fields.

8.1. Example

In this example we use two forms nested in a FormCollection. Remember, a Fieldset behaves exactly as a Form instance and can be used as a replacement, although with additional styling possibilities.

from django.forms import fields, forms
from formset.fieldset import Fieldset
from formset.collection import FormCollection

class CustomerForm(Fieldset):
    legend = "Customer"
    hide_if = 'register.no_customer'
    recipient = fields.CharField()
    address = fields.CharField()

class RegisterForm(forms.Form):
    no_customer = fields.BooleanField(
        label="I'm not a customer",
        required=False,
    )

class CustomerCollection(FormCollection):
    customer = CustomerForm()
    register = RegisterForm()

When rendered, this Form Collection may look like:

Fieldset

The interesting part of this collection is that we can hide the fieldset by clicking on the checkbox named “I’m not a customer”. This means that by using conditionals, we can dynamically adjust the visibility of a complete form.