Forms

ToscaWidgets provides all the widgets related to building HTML Forms in the tw2.forms package.

While tw2.core implements the foundation for declaring any kind of widget, the tw2.forms is specialised in widgets that are needed to create HTML forms.

Form

A form is usually created by declaring a subclass of a tw2.forms.Form. Within the form a child attribute that specifies the Form Layout (how the fields shoulb be arranged graphically) through a subclass of tw2.forms.Layout and then within child all the fields of the form can be declared:

import tw2.core as twc
import tw2.forms as twf


class MovieForm(twf.Form):
    class child(twf.TableLayout):
        title = twf.TextField()
        director = twf.TextField(value='Default Director')
        genres = twf.SingleSelectField(options=['Action', 'Comedy', 'Romance', 'Sci-fi'])

    action = '/save_movie'

The form must also provide an action attribute to specify where the form should be submitted.

Note

If you are going to use ToscaWidgets with TurboGears you probably want the action to be a tg.lurl to ensure that prefix of your application is retained.

Form Buttons

By default, each form comes with a submit button.

The submit button can be replaced by setting the form submit attribute:

class NameForm(twf.Form):
    class child(twf.TableLayout):
        name = twf.TextField()

    action = '/save_name'
    submit = twf.SubmitButton(value="Save Name")

Multiple buttons can also be provided for the form by setting the buttons attribute:

class NameForm(twf.Form):
    class child(twf.TableLayout):
        name = twf.TextField()

    action = '/save_name'
    buttons = [
        twf.SubmitButton(value="Save Name"),
        twf.ResetButton(),
        twf.Button(value="Say Hi", attrs=dict(onclick="alert('hi')"))
    ]

Dynamic Forms

Children can be added and removed dynamically from forms using the Widget.post_define() and Widget.prepare() methods.

For example to change children of a form based on an option, Widget.post_define() can be used:

class GrowingMovieForm(twf.Form):
    class child(twf.TableLayout):
        @classmethod
        def post_define(cls):
            if not cls.parent:
                return

            children = []

            for count in range(cls.parent.num_contacts):
                class person_fieldset(twf.TableFieldSet):
                    id = "person_%s" % count
                    label = "Person #%s" % count
                    name = twf.TextField(validator=twc.Validator(required=True))
                    surname = twf.TextField()

                children.append(person_fieldset(parent=cls))

            cls.children = children

    action = '/save_contacts'
    num_contacts = twc.Param(default=1)

fivefieldsform = GrowingMovieForm(num_contacts=5)

Note

Use the same fivefieldsform object for both display and validation. Trying to make a new GrowingMovieForm might not work even though num_contacts is always set to 5.

This will not work btw if you need to take action at display time. In such case Widget.prepare() is needed, for example to have a text field that suggests the placeholder based on its original value:

class DynamicText(twf.Form):
    class child(twf.TableLayout):
        text = twf.TextField(placeholder="Put text here")

    action = "/save_movie"

    def prepare(self):
        super(DynamicText, self).prepare()

        if self.child.children.text.value:
            self.child.children.text.attrs = dict(
                self.child.children.text.attrs,
                placeholder="Put text here (was %s)" % self.child.children.text.value
            )

Note

Widget.prepare() is usually involved when setting a state that depends on the current request. For example current value of a field, or something else that is known only in current request. The resulting state of the widget is also only valid in current request, a different request might have nothing in common. Keep this in mind when using validation, as validation usually happens in a different request from the one that displayed the widget.

class tw2.forms.widgets.Form(**kw)[source]

A form, with a submit button. It’s common to pass a TableLayout or ListLayout widget as the child.

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
submit

alias of tw2.core.params.SubmitButton_s_s

Validating Forms

When you submit a form, it will send its data to the endpoint you specified through the action parameter.

Before using it, you probably want to make sure that the data that was sent is correct and display back to the user error messages when it is not.

This can be done through Validation and thanks to the fact that Forms remember which form was just validated in the current request.

For each field in the form it is possible to specify a validator= parameter, which will be in charge of validation for that field:

class ValidatedForm(twf.Form):
    class child(twf.TableLayout):
        number = twf.TextField(placeholder="a number (1, 2, 3, 4)",
                               validator=twc.validation.IntValidator())
        required = twf.TextField(validator=twc.Required)

To validate the data submitted through this form you can use the tw2.forms.widgets.Form.validate() method.

If the validation passes, the method will return the validated data:

>>> ValidatedForm.validate({'numer': 5, 'required': 'hello'})
{'numer': 5, 'required': 'hello'}

If the validation fails, it will raise a tw2.core.validation.ValidationError exception:

Traceback (most recent call last):
    File "/home/amol/wrk/tw2.core/tw2/core/validation.py", line 106, in wrapper
        d = fn(self, *args, **kw)
    File "/home/amol/wrk/tw2.core/tw2/core/widgets.py", line 718, in _validate
        raise vd.ValidationError('childerror', exception_validator)
tw2.core.validation.ValidationError

Such error can be trapped to get back the validated widget, the value that was being validated and the error message for each of its children:

>>> try:
...     ValidatedForm.validate({'numer': 'Hello', 'required': ''})
... except tw2.core.validation.ValidationError as e:
...     print(e.widget.child.value)
...     for c in e.widget.child.children:
...         print(c.compound_key, ':', c.error_msg)

{'numer': 'Hello', 'required': ''}
numer : Must be an integer
required : Enter a value

Also, trying to display back the form that was just validated, will print out the error message for each field:

>>> try:
...     ValidatedForm.validate({'numer': 'Hello', 'required': ''})
... except tw2.core.validation.ValidationError as e:
...     print(e.widget.display())

<form enctype="multipart/form-data" method="post">
    <span class="error"></span>

    <table>
    <tr class="odd error" id="numer:container">
        <th><label for="numer">Numer</label></th>
        <td>
            <input id="numer" name="numer" placeholder="a number (1, 2, 3, 4)" type="text" value="Hello"/>
            <span id="numer:error">Must be an integer</span>
        </td>
    </tr><tr class="even required error" id="required:container">
        <th><label for="required">Required</label></th>
        <td>
            <input id="required" name="required" type="text" value=""/>
            <span id="required:error">Enter a value</span>
        </td>
    </tr>
    </table>
    <input type="submit" value="Save"/>
</form>

For convenience, you can also recover the currently validated instance of the form anywhere in the code. Even far away from the exception that reported the validation error.

This can be helpful when you are isolating validation into a separate Aspect of your application and then you need to recover the form instance that includes the errors to display into your views.

To retrieve the currently validated widget, you can just use tw2.core.widget.Widget.req():

>>> try:
...     ValidatedForm.validate({'numer': 'Hello', 'required': ''})
... except tw2.core.validation.ValidationError as e:
...     print(e.widget)
...     print(ValidatedForm.req())

<__main__.ValidatedForm object at 0x7f9432e5e080>
<__main__.ValidatedForm object at 0x7f9432e5e080>

As you can see ValidatedForm.req() returns the same exact instance that e.widget was. That’s because when Widget.req() is used and there is a validated instance of that same exact widget in the current request, ToscaWidgets will assume you are trying to access the widget you just validated and will return that one instace of building a new instance.

If you want a new instance, you can still do ValidatedForm().req() instead of ValidatedForm.req():

>>> try:
...     ValidatedForm.validate({'numer': 'Hello', 'required': ''})
... except tw2.core.validation.ValidationError as e:
...     print(e.widget)
...     print(ValidatedForm().req())

<__main__.ValidatedForm object at 0x7f9432e5e080>
<tw2.core.params.ValidatedForm_d object at 0x7f9432420940>

Keep in mind that this only keeps memory of the last widget that failed validation. So in case multiple widgets failed validation in the same request, you must used tw2.core.validation.ValidationError.widget to access each one of them.

Form Layout

A layout specifies how the fields of the form should be arranged.

This can be specified by having Form.child inherit from a specific layout class:

class NameForm(twf.Form):
    class child(twf.TableLayout):
        name = twf.TextField()

or:

class NameForm(twf.Form):
    class child(twf.ListLayout):
        name = twf.TextField()

Custom Layouts

A custom layout class can also be made to show the children however you want:

class Bootstrap3Layout(twf.BaseLayout):
    inline_engine_name = "kajiki"
    template = """
<div py:attrs="w.attrs">
    <div class="form-group" py:for="c in w.children_non_hidden" title="${w.hover_help and c.help_text or None}" py:attrs="c.container_attrs" id="${c.compound_id}:container">
        <label for="${c.id}" py:if="c.label">$c.label</label>
        ${c.display(attrs={"class": "form-control"})}
        <span id="${c.compound_id}:error" class="error help-block" py:content="c.error_msg"/>
    </div>
    <py:for each="c in w.children_hidden">${c.display()}</py:for>
    <div id="${w.compound_id}:error" py:content="w.error_msg"></div>
</div>"""

class BootstrapNameForm(twf.Form):
    class child(Bootstrap3Layout):
        name = twf.TextField()

    submit = twf.SubmitButton(css_class="btn btn-default")

Complex Layouts

In case of complex custom layouts, you can even specify the layout case by case in the form itself with each children in a specific position accessing the children using w.children.child_name:

class OddNameForm(twf.Form):
    class child(twf.BaseLayout):
        inline_engine_name = "kajiki"
        template = """
        <div py:attrs="w.attrs">
            <div py:with="c=w.children.name">
                ${c.display()}
                <span id="${c.compound_id}:error" py:content="c.error_msg"/>
            </div>
            <div py:with="c=w.children.surname">
                ${c.display()}
                <span id="${c.compound_id}:error" py:content="c.error_msg"/>
            </div>

            <py:for each="ch in w.children_hidden">${ch.display()}</py:for>
            <div id="${w.compound_id}:error" py:content="w.error_msg"></div>
        </div>
        """

        name = twf.TextField()
        surname = twf.TextField()
class tw2.forms.widgets.BaseLayout(**kw)[source]

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
prepare()[source]

Propagate the value for this widget to the children, based on their id.

class tw2.forms.widgets.ListLayout(**kw)[source]

Arrange widgets and labels in a list.

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
class tw2.forms.widgets.TableLayout(**kw)[source]

Arrange widgets and labels in a table.

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
class tw2.forms.widgets.GridLayout(**kw)[source]

Arrange labels and multiple rows of widgets in a grid.

child

alias of tw2.core.params.RowLayout_s

class tw2.forms.widgets.RowLayout(**kw)[source]

Arrange widgets in a table row. This is normally only useful as a child to GridLayout.

prepare()[source]

Propagate the value for this widget to the children, based on their id.

Bultin Form Fields

tw2.forms package comes with a bunch of builtin widgets that can help you build the most common kind of forms.

class tw2.forms.widgets.FormField(**kw)[source]

Basic Form Widget from which each other field will inherit

name

Name of the field

required

If the field is required according to its validator (read-only)

class tw2.forms.widgets.TextFieldMixin(**kw)[source]

Misc mixin class with attributes for textual input fields

maxlength = None

Maximum length of the field

placeholder = None

Placeholder text, until user writes something.

class tw2.forms.widgets.InputField(**kw)[source]

A generic <input> field.

Generally you won’t use this one, but will rely on one of its specialised subclasses like TextField or Checkbox.

type = None

Input type

value = None

Current value of the input

required = None

Add required attributed to the input.

autofocus = None

Add autofocus attributed to the input.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.PostlabeledInputField(**kw)[source]

Inherits InputField, but with a text label that follows the input field

text = None

Text to display in the label after the field.

text_attrs = {}

Attributes of the label displayed after to the field.

class tw2.forms.widgets.TextField(**kw)[source]

A simple text field where to input a single line of text

size = None

Add size attribute to the HTML field.

class tw2.forms.widgets.TextArea(**kw)[source]

A multiline text area

rows = None

Add a rows= attribute to the HTML textarea

cols = None

Add a cols= attribute to the HTML textarea

class tw2.forms.widgets.CheckBox(**kw)[source]

A single checkbox.

Its value will be True or Folse if selected or not.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.RadioButton(**kw)[source]

A single radio button

checked = False

If the radio button is checked or not.

class tw2.forms.widgets.PasswordField(**kw)[source]

A password field. This never displays a value passed into the widget, although it does redisplay entered values on validation failure. If no password is entered, this validates as EmptyField.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.FileValidator(**kw)[source]

Validate a file upload field

extension
Allowed extension for the file
class tw2.forms.widgets.FileField(**kw)[source]

A field for uploading files. The returned object has (at least) two properties of note:

  • filename:
    the name of the uploaded file
  • value:
    a bytestring of the contents of the uploaded file, suitable for being written to disk
prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.HiddenField(**kw)[source]

A hidden field.

Typically this is used to bring around in the form values that the user should not be able to modify or see. Like the ID of the entity edited by the form.

class tw2.forms.widgets.IgnoredField(**kw)[source]

A hidden field. The value is never included in validated data.

class tw2.forms.widgets.LabelField(**kw)[source]

A read-only label showing the value of a field. The value is stored in a hidden field, so it remains through validation failures. However, the value is never included in validated data.

class tw2.forms.widgets.LinkField(**kw)[source]

A dynamic link based on the value of a field. If either link or text contain a $, it is replaced with the field value. If the value is None, and there is no default, the entire link is hidden.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.Button(**kw)[source]

Generic button. You can override the text using value and define a JavaScript action using attrs[‘onclick’].

class tw2.forms.widgets.SubmitButton(**kw)[source]

Button to submit a form.

class tw2.forms.widgets.ResetButton(**kw)[source]

Button to clear the values in a form.

class tw2.forms.widgets.ImageButton(**kw)[source]
prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.HTML5PatternMixin(**kw)[source]

HTML5 mixin for input field regex pattern matching

See http://html5pattern.com/ for common patterns.

TODO: Configure server-side validator

class tw2.forms.widgets.HTML5MinMaxMixin(**kw)[source]

HTML5 mixin for input field value limits

TODO: Configure server-side validator

class tw2.forms.widgets.HTML5StepMixin(**kw)[source]

HTML5 mixin for input field step size

class tw2.forms.widgets.HTML5NumberMixin(**kw)[source]

HTML5 mixin for number input fields

class tw2.forms.widgets.EmailField(**kw)[source]

An email input field (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.UrlField(**kw)[source]

An url input field (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.NumberField(**kw)[source]

A number spinbox (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.RangeField(**kw)[source]

A number slider (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.SearchField(**kw)[source]

A search box (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.ColorField(**kw)[source]

A color picker field (HTML5 only).

Will fallback to a normal text input field on browser not supporting HTML5.

class tw2.forms.widgets.SelectionField(**kw)[source]

Base class for single and multiple selection fields.

The options parameter must be a list; it can take several formats:

  • A list of values, e.g. ['', 'Red', 'Blue']
  • A list of (code, value) tuples, e.g. [(0, ''), (1, 'Red'), (2, 'Blue')]
  • A mixed list of values and tuples. If the code is not specified, it defaults to the value. e.g. ['', (1, 'Red'), (2, 'Blue')]
  • Attributes can be specified for individual items, e.g. [(1, 'Red', {'style':'background-color:red'})]
  • A list of groups, e.g. [('group1', [(1, 'Red')]), ('group2', ['Pink', 'Yellow'])]

Setting value before rendering will set the default displayed value on the page. In ToscaWidgets1, this was accomplished by setting default. That is no longer the case.

options = None

List of options to pick from in the form [(id, text), (id, text), ...]

prompt_text = None

Prompt to display when no option is selected. Set to None to disable this.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.MultipleSelectionField(**kw)[source]
item_validator = None

Validator that has to be applied to each item.

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.SingleSelectField(**kw)[source]

Specialised SelectionField to pick one element from a list of options.

class tw2.forms.widgets.MultipleSelectField(**kw)[source]

Specialised SelectionField to pick multiple elements from a list of options.

size = None

Number of options to show

class tw2.forms.widgets.SelectionList(**kw)[source]
class tw2.forms.widgets.SeparatedSelectionTable(**kw)[source]
class tw2.forms.widgets.RadioButtonList(**kw)[source]
class tw2.forms.widgets.CheckBoxList(**kw)[source]
class tw2.forms.widgets.SelectionTable(**kw)[source]
prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.VerticalSelectionTable(**kw)[source]
prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.RadioButtonTable(**kw)[source]
class tw2.forms.widgets.SeparatedRadioButtonTable(**kw)[source]
class tw2.forms.widgets.VerticalRadioButtonTable(**kw)[source]
class tw2.forms.widgets.CheckBoxTable(**kw)[source]
class tw2.forms.widgets.SeparatedCheckBoxTable(**kw)[source]
class tw2.forms.widgets.VerticalCheckBoxTable(**kw)[source]
class tw2.forms.widgets.BaseLayout(**kw)[source]

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
prepare()[source]

Propagate the value for this widget to the children, based on their id.

class tw2.forms.widgets.TableLayout(**kw)[source]

Arrange widgets and labels in a table.

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
class tw2.forms.widgets.ListLayout(**kw)[source]

Arrange widgets and labels in a list.

The following CSS classes are used, on the element containing both a child widget and its label.

odd / even
On alternating rows. The first row is odd.
required
If the field is a required field.
error
If the field contains a validation error.
class tw2.forms.widgets.RowLayout(**kw)[source]

Arrange widgets in a table row. This is normally only useful as a child to GridLayout.

prepare()[source]

Propagate the value for this widget to the children, based on their id.

class tw2.forms.widgets.StripBlanks(**kw)[source]
to_python(value, state=None)[source]

Convert an external value to Python and validate it.

class tw2.forms.widgets.GridLayout(**kw)[source]

Arrange labels and multiple rows of widgets in a grid.

child

alias of tw2.core.params.RowLayout_s

class tw2.forms.widgets.Spacer(**kw)[source]

A blank widget, used to insert a blank row in a layout.

class tw2.forms.widgets.Label(**kw)[source]

A textual label. This disables any label that would be displayed by a parent layout.

class tw2.forms.widgets.Form(**kw)[source]

A form, with a submit button. It’s common to pass a TableLayout or ListLayout widget as the child.

classmethod post_define()[source]

This is a class method, that is called when a subclass of this Widget is created. Process static configuration here. Use it like this:

class MyWidget(LeafWidget):
    @classmethod
    def post_define(cls):
        id = getattr(cls,  'id', None)
        if id and not id.startswith('my'):
            raise pm.ParameterError("id must start with 'my'")

post_define should always cope with missing data - the class may be an abstract class. There is no need to call super(), the metaclass will do this automatically.

submit

alias of tw2.core.params.SubmitButton_s_s

prepare()[source]

This is an instance method, that is called just before the Widget is displayed. Process request-local configuration here. For efficiency, widgets should do as little work as possible here. Use it like this:

class MyWidget(Widget):
    def prepare(self):
        super(MyWidget, self).prepare()
        self.value = 'My: ' + str(self.value)
class tw2.forms.widgets.FieldSet(**kw)[source]

A field set. It’s common to pass a TableLayout or ListLayout widget as the child.

class tw2.forms.widgets.TableForm(**kw)[source]

Equivalent to a Form containing a TableLayout.

child

alias of tw2.core.params.TableLayout_s

submit

alias of tw2.core.params.SubmitButton_s_s_s

class tw2.forms.widgets.ListForm(**kw)[source]

Equivalent to a Form containing a ListLayout.

child

alias of tw2.core.params.ListLayout_s

submit

alias of tw2.core.params.SubmitButton_s_s_s

class tw2.forms.widgets.TableFieldSet(**kw)[source]

Equivalent to a FieldSet containing a TableLayout.

child

alias of tw2.core.params.TableLayout_s

class tw2.forms.widgets.ListFieldSet(**kw)[source]

Equivalent to a FieldSet containing a ListLayout.

child

alias of tw2.core.params.ListLayout_s

class tw2.forms.widgets.FormPage(**kw)[source]

A page that contains a form. The request method performs validation, redisplaying the form on errors. On success, it calls validated_request.