Skip to content

Forms

TypeSystem gives you form rendering support, which you can either style and customize yourself, or use together with a pre-packaged theme.

Let's take a look:

import typesystem

forms = typesystem.Jinja2Forms(package="typesystem")  # Use the default templates.

booking_schema = typesystem.Schema(
    fields={
        "start_date": typesystem.Date(title="Start date"),
        "end_date": typesystem.Date(title="End date"),
        "room": typesystem.Choice(title="Room type", choices=[
            ('double', 'Double room'),
            ('twin', 'Twin room'),
            ('single', 'Single room')
        ]),
        "include_breakfast": typesystem.Boolean(title="Include breakfast", default=False),

    }
)

form = forms.create_form(booking_schema)
print(form)

That'll render an HTML form which looks something like this:

Default form rendering

The default templates included by typesystem use tables to provide a simple functional layout.

Notice that only the fields in the form are rendered. The surrounding <form>, <table>, and <input type="submit"> tags should be included directly in any template that renders the form.

<tr>
    <td>
        <label for="start-date">Start date</label>
    </td>
    <td>
        <input type="date" id="start-date" name="start_date" required >
    </td>
</tr>
<tr>
    <td>
        <label for="end-date">End date</label>
    </td>
    <td>
        <input type="date" id="end-date" name="end_date" required >
    </td>
</tr>
<tr>
    <td>
        <label for="room">Room type</label>
    </td>
    <td>
        <select id="room" name="room">
            <option></option>
            <option value="double">Double room</option>
            <option value="twin">Twin room</option>
            <option value="single">Single room</option>
        </select>
    </td>
</tr>
<tr>
    <td>
        <label for="include-breakfast">Include breakfast</label>
    </td>
    <td>
        <input type="checkbox" id="include-breakfast" name="include_breakfast" value="true" >
    </td>
</tr>

You can include a form inside a Jinja2 template by passing it as context, and rendering the context value. Make sure to include the surrounding tags:

<form action="/" method="POST">
    <table>
        {{ form }}
        <tr>
            <td></td>
            <td><input type="submit" value="Make booking"/></td>
        </tr>
    </table>
</form>

Including values and errors

We can include values in a form like so:

initial_values = {'room': 'double', 'include_breakfast': True}
form = forms.create_form(booking_schema, values=initial_values)

Customizing field rendering

If you'd like to override the default field rendering you can switch to using your own custom templates. Switch this line:

forms = typesystem.Jinja2Forms(package="typesystem")

To instead use a templates directories:

forms = typesystem.Jinja2Forms(directory="templates")

You'll need to provide the following templates:

  • forms/checkbox.html
  • forms/input.html
  • forms/select.html
  • forms/textarea.html

Using a packaged theme

You can also use a pre-packaged theme, such as Bootstrap 4:

# This pypi package includes `typesystem` form templates,
# and pre-packaged static files.
$ pip install bootstrap4
forms = typesystem.Jinja2Forms(package="bootstrap4")

The bootstrap4 package also provides the static CSS and JavaScript files, which you can easily serve up from Starlette's StaticFiles application:

# Serve everything in the local "statics" directory plus everything
# in the "statics" directory of the `bootstrap4` package.
statics = StaticFiles(directory="statics", packages=["bootstrap4"])

That will then render HTML forms using Bootstrap:

Bootstrap form rendering