======= Forms ======= The :term:`form` is the workhorse of the general CRUD features. * When viewing a record, a *readonly* form is displayed. * When creating or editing a record, the form is *not* readonly. * When deleting, the form is technically not readonly, but all fields *are* readonly. WuttaWeb provides the :class:`~wuttaweb.forms.base.Form` class; the :class:`~wuttaweb.views.master.MasterView` class will instantiate these within the CRUD views. Under the hood, these libraries are used: * :doc:`colander:index` * :doc:`colanderalchemy:index` * :doc:`deform:index` Colander provides the schema (node/type info) for the fields and form overall. Deform provides the widget/HTML rendering and related things. Lifecycle --------- Generally speaking, when a request comes in, the view creates a form. If it was a POST request, the view asks the form to validate the submitted data. If it was valid, the data is saved and user is sent a redirect. If it was not, the form is re-displayed to the user with validation errors shown. From the perspective of the :class:`~wuttaweb.forms.base.Form` class, there are sort of 2 phases: before and after the schema is generated. The view creates and configures the form *before* the schema actually gets created. During configuration, the view can add, modify or remove fields as needed. When a form is to be validated or rendered, it will automatically create the schema and associated Deform objects. See also: * :meth:`~wuttaweb.views.master.MasterView.make_model_form()` * :meth:`~wuttaweb.views.master.MasterView.configure_form()` * :meth:`~wuttaweb.forms.base.Form.validate()` * :meth:`~wuttaweb.views.master.MasterView.objectify()` * :meth:`~wuttaweb.views.master.MasterView.persist()` Fields ------ During the configuration phase, the form only has "potential" fields. They become "actual" field instances when the form creates its schema. WuttaWeb does not define a ``Field`` class; rather it uses the Deform and Colander API to represent these: * the field itself (instance of :class:`deform:deform.field.Field`) * the field has a corresponding "node" (instance of :class:`colander:colander.SchemaNode`) within form schema * the node has a "type" (instance of :class:`colander:colander.SchemaType`) * the field also has a "widget" (instance of :class:`deform:deform.widget.Widget`) Configuration ------------- The form can be configured "reliably" until the form schema is created. After that point, some configuration may be limited. So as a rule, you should avoid *causing* the form to create its schema within the configuration phase. The form auto-creates the schema whenever :meth:`~wuttaweb.forms.base.Form.get_schema()` or :meth:`~wuttaweb.forms.base.Form.get_deform()` are called. Here are some common :class:`~wuttaweb.forms.base.Form` methods used for configuration: * :meth:`~wuttaweb.forms.base.Form.append()` * :meth:`~wuttaweb.forms.base.Form.remove()` * :meth:`~wuttaweb.forms.base.Form.set_autofocus()` * :meth:`~wuttaweb.forms.base.Form.set_default()` * :meth:`~wuttaweb.forms.base.Form.set_grid()` * :meth:`~wuttaweb.forms.base.Form.set_label()` * :meth:`~wuttaweb.forms.base.Form.set_node()` * :meth:`~wuttaweb.forms.base.Form.set_readonly()` * :meth:`~wuttaweb.forms.base.Form.set_required()` * :meth:`~wuttaweb.forms.base.Form.set_validator()` * :meth:`~wuttaweb.forms.base.Form.set_widget()` You can also access the :attr:`~wuttaweb.forms.base.Form.fields` attribute directly, for more control over the field list.