Form

Base class: Part

Describe a Form. Example:

class MyForm(Form):
    a = Field()
    b = Field.email()

form = MyForm().bind(request=request)

You can also create an instance of a form with this syntax if it’s more convenient:

form = Form(
    fields=dict(
        a=Field(),
        b=Field.email(),
    ),
).bind(request=request)

In the common case the fields namespace will contain only instances of Field, but iommi actually supports arbitrary Part objects. For example:

form = Form(
    fields=dict(
        # Display a and b inside a box
        box=html.div(
            attrs__class__box=True,
            children__a=Field(),
            children__b=Field.email(),
        ),
        # And c regularly
        c=Field(),
    )
)

So that writing the application logic (e.g. validation and post handlers) is independent of minor changes to the layout, after bind the fields namespace of the form will contain only instances of Field keyed by their _name independently of how deep they are in the hierarchy. Given the above, an appropriate post_handler would be:

def post_handler(form, **_):
    if not form.is_valid():
        return

    print(form.fields.a.value, form.fields.b.value, form.fields.c.value)
    # And not:
    # print(form.fields.box.a.value, form.fields.box.b.value, form.fields.c.value)

Use of Form.layout:

from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy
from iommi._web_compat import Template

class UserForm(Form):
    class Meta:
        auto__model = get_user_model()
        layout = Panel(dict(
            p_main=Panel.fieldset(dict(
                username=Panel.field(),
                p_fullname=Panel.row(dict(
                    first_name=Panel.field(col__attrs__class__firstname=True),
                    last_name=Panel.field(),
                )),
                # examples of custom html parts:
                p_foo=Panel.row(dict(
                    p_bar=gettext_lazy('Some plain text'),
                    p_baz=Template('{% load i18n %}<span>{% translate "Foobar!" %}</span>'),
                )),
                p_qux=Fragment(template='path/to/template.html'),
                p_quux=html.h3('Quux'),
                p_corge__template='path/to/another_template.html',
            )),
            p_permissions=Panel.fieldset(dict(
                # ...
            )),
            p_error=Panel.alert('Error!', level='error'),
        ))

Refinable members

action_class

Type: Type[Action]

actions

Type: Namespace

actions_template     (evaluated)

Type: Union[str, Template]

Default: iommi/form/actions.html

after     (evaluated)

Type: Union[int, str]

See after

assets

Type: Namespace

See assets

attr     (evaluated)

Type: str

See attr

attrs     (evaluated)

Type: Attrs

Cookbook:

How do I make a freetext search field?

auto

Type: FormAutoConfig

See auto

Cookbook:

How do I enable a reverse foreign key relationship?

How do I say which fields to include when creating a form from a model?

editable

Type: bool

Default: True

Cookbook:

How do I make a field non-editable?

endpoints

Type: Namespace

errors

Type: Errors

Cookbook:

How do I create a hidden field?

extra

Type: Dict[str, Any]

See extra

Cookbook:

How do I change where the form redirects to after completion?

extra_evaluated

Type: Dict[str, Any]

See extra

extra_params

field_group

Type: Namespace

fields

Type: Namespace

Cookbook:

How do I make a fields choices depend on another field?

How do I nest multiple forms?

fields_template     (evaluated)

Type: Union[str, Template]

Cookbook:

How do I use templates for fields?

h_tag     (evaluated)

Type: Union[Fragment, str]

See title

include     (evaluated)

Type: bool

See include

instance

Type: Any

iommi_style

Type: str

layout     (evaluated)

Type: Optional[Panel]

layout_render_unused_fields     (evaluated)

Type: bool

Default: False

layout_template     (evaluated)

Type: Union[NoneType, str, Template]

Default: lambda form, **_: 'iommi/form/layout.html' if form.layout is not None else None

member_class

Type: Type[Field]

model     (evaluated)

Type: Type[Model]

page_class

Type: Type[Page]

post_validation

read_nested_form_from_instance

Read the nested forms instance from the parent forms instance.

This is analogous to Field.read_from_instance but for nested forms.

template     (evaluated)

Type: Union[str, Template]

Default: iommi/form/form.html

See template

title     (evaluated)

Type: Fragment

See title

write_nested_form_to_instance

Write the nested_form to the instance.

This is analogous to Field.write_to_instance but for nested forms.

Shortcuts

Form.create

Parent: Form.crud

Defaults

  • actions__submit__post_handler
    • iommi.form.create_object__post_handler

  • extra__is_create
    • True

Form.create_or_edit

Parent: Form.crud

Defaults

  • actions__submit__post_handler
    • iommi.form.create_or_edit_object__post_handler

  • extra__is_create
    • None

Cookbook:

How do I make a create or edit form?

Form.crud

Defaults

  • extra__pre_save_all_but_related_fields
    • lambda **kwargs: None, # pragma: no mutate

  • extra__on_save_all_but_related_fields
    • lambda **kwargs: None, # pragma: no mutate

  • extra__pre_save
    • lambda **kwargs: None, # pragma: no mutate

  • extra__on_save
    • lambda **kwargs: None, # pragma: no mutate

  • extra__on_delete
    • lambda **kwargs: None, # pragma: no mutate

  • extra__redirect
    • lambda redirect_to, **_: HttpResponseRedirect(redirect_to)

  • extra__redirect_to
    • None

  • extra__crud_type
    • lambda form, **_: 'create' if form.instance is None else 'edit'

  • extra__new_instance
    • lambda form, **_: form.model()

  • auto
    • Namespace()

Form.delete

Parent: Form.crud

Defaults

  • actions__submit__call_target__attribute
    • delete

  • actions__submit__post_handler
    • iommi.form.delete_object__post_handler

  • extra__crud_type
    • delete

  • editable
    • False

  • fields__iommi_default_text
    • {'call_target': <class 'iommi.fragment.Fragment'>, 'include': <function Form.<lambda> at 0x7eb20c68c180>, 'after': 0, 'tag': 'p', 'children__text': <function Form.<lambda> at 0x7eb20c68c720>}

Form.edit

Parent: Form.crud

Defaults

  • actions__submit__post_handler
    • iommi.form.edit_object__post_handler

  • extra__is_create
    • False

Methods

add_error

Explicitly add an error message to the form’s global error set.

Example:

def post_validation(form, **_):
    form.add_error('global error')

form = Form.create(
    auto__model=Album,
    post_validation=post_validation,
)
▼ Hide result
Toggle structure

apply

Write the new values specified in the form into the instance specified.

as_view

get_errors

Get a dict containing two keys:

  • global for errors global to the entire form.

  • fields for errors specific to fields. This is itself a dict with a key for each field.

get_field

get_nested_form

is_target

is_valid

Is the form valid? Can be called inside forms post_validation hook to determine if the individual fields were all valid.

on_bind

on_refine_done

own_evaluate_parameters

validate

Static methods

apply_field

Class methods

fields_from_model