flatland’s design stems from a few basic tenets:

  • All input is suspect
  • Input can come from multiple sources and interfaces
  • Bad input isn’t exceptional: it is expected

With flatland, you describe exactly what elements your form may contain. Forms extract and process only their known elements out of the (key, value) input data. Unexpected or malicious data will not be processed.

The description of forms and their fields is data-centric rather than HTML or interface-centric. In a flatland form schema, a password input field is simply a string, not a “PasswordInput” or the like. The decision about how to represent that field is left up to another layer entirely. Maybe you do want an <input type="password"> control, or maybe <input type="hidden"> in some cases, or sometimes the data is coming in as JSON. flatland can act as another type of M in your M/VC, MC, MVC or MTV.

Humans are imperfect and filling out forms will always be error-prone. flatland recognizes this and provides features to make error detection and correction part of the regular workflow of a form. By default, validation routines will consider every element of a form and mark all problematic fields, allowing users to take action on all issues at once.


Field schemas define all possible fields the form may contain. A schema may a single field, a collection of fields, or an even richer structure. Nested mappings and lists of fields are supported, as well as compound fields and even more exotic types.

from flatland import Form, String

class SignInForm(Form):
    username = String
    password = String

Field schemas are long-lived objects similar to class definitions. The instantiations of a flatland schema are called data elements, a tree structure of data-holding objects. The elements of a flatland form may be initiated blank, using default values, or with values taken from your objects.

form = SignInForm.from_flat(request.POST)
if form.validate():
    logging.info(u"sign-in: %s" % form['username'].value)
    render('login.html', form=form)

Elements are rich objects that validate and normalize input data as well as hold field-level error and warning messages. Elements can be exported to a native Python structure, flattened back into Unicode (key, value) pairs or used as-is in output templates for form layout, redisplay and error reporting.

>>> as_regular_python_data = form.value
>>> type(as_regular_python_data)
<type 'dict'>
>>> as_regular_python_data['username']
>>> form2 = SignInForm(as_regular_python_data)
>>> assert form['username'].value == form2['username'].value