Forms

iommi forms is an alternative forms system for Django. It is inspired by, and comes from a frustration with, the standard Django forms.

Major features compared to Django forms:

  • Supports __ syntax for going across table/object boundaries, similar to how Django does with QuerySets.
  • Send in a callable that is late evaluated to determine if a field should be displayed (include). This is very handy for showing a slightly different form to administrators for example.
  • Easy configuration without writing entire classes that are only used in one place anyway.

Read the full documentation and the HOWTO for more.

Example

You can either create a subclass of Form

class UserForm(Form):
    name = Field.text()
    username = Field.text(
        is_valid=lambda parsed_data, **_: parsed_data.startswith('demo_'))
    is_admin = Field.boolean(
        # show only for staff
        include=lambda request, **_: request.user.is_staff,
        label_template='tweak_label_tag.html')

def edit_user_view(request, username):
    form = UserForm(request=request)

    user = User.objects.get(username=username)
    if form.is_valid() and get_request.method == 'POST':
        form.apply(user)
        user.save()
        return HttpRedirect('..')

    return render(
        template_name='edit_user.html',
        context_instance=RequestContext(request, {'form': form}))
<!-- edit_user.html -->
<form action="" method="post">{% csrf_token %}
  <div>
    <table>
      {{ form }}
    </table>
  </div>
  <input type="submit" value="Save" />
</form>

or just instantiate a Form with a Field list and use it directly:

def edit_user_view(request, username):
    form = Form(fields=dict(
        name=Field.text(
            is_valid=lambda parsed_data, **_: parsed_data.startswith('demo_'),
        ),
        username=Field.text(),
        is_admin=Field.boolean(
            # show only for staff
            include=lambda request, **_: request.user.is_staff,
            label_template='tweak_label_tag.html',
        ),
    ])

    # rest of view function...

You can also generate forms from Django models automatically (but still change the behavior!). The above example is equivalent to:

def edit_user_view(request, username):
    form = Form(
        auto__model=User,
        # the field 'name' is generated automatically and
        # we are fine with the defaults
        username__is_valid=
            lambda parsed_data, **_: parsed_data.startswith('demo_'),
        is_admin__label_template='tweak_label_tag.html',
        # show only for staff
        is_admin__include=lambda request, **_: request.user.is_staff,
    )
    form = form.bind(request=request)

    # rest of view function...

or even better: use Form.edit:

def edit_user_view(request, username):
    return Form.edit(
        model=User,
        instance=User.objects.get(username=username),
        username__is_valid=
            lambda parsed_data, **_: parsed_data.startswith('demo_'),
        is_admin__label_template='tweak_label_tag.html',
        # show only for staff
        is_admin__include=lambda request, **_: request.user.is_staff,
    )
    # no html template! iommi has a nice default for you :P

iommi pre-packages sets of defaults for common field types as ‘shortcuts’. Some examples include Field.boolean, Field.integer and Field.choice. The full list of shortcuts can be found in the API documentation for Field.