Using Forms

A Simple Form

This is the core of Yota’s functionality. To create a Form with Yota you must inherit from the From superclass like in the following example.

from yota import Form
from yota.nodes import *

class PersonalForm(Form):

    first = EntryNode()
    last = EntryNode()
    address = EntryNode()
    submit = SubmitNode(title="Submit")

Forms are simply a collection of Nodes and Checks. The Checks drive validation of the Form and will be talked about next, while the Nodes drive rendering. Conceptually Nodes can be thought of as a single input section in your form, but it can actually be anything that is destined to generate some HTML or Javascript in your Form. For example you may wish to place a header at the beginning to the Form even though it isn’t used for any data entry. Most keyword arguments passed to a Node are passed directly to their rendering context, and thus their use is completely up to user choice. More information on Nodes can be found in the Nodes documentation section. Your new Form class inherits lots of functionality for common tasks such as rendering and validation.

To render our Form we can call the Form.render() function on an instance of our Form object:

>>> personal = PersonalForm()
>>> personal.render()
'<form method="post">
...
</form>'

As talked about in the Node documentation, each Node by default has an associated template that is used to render it. The render function essentially passes the list of Nodes in the Form onto the Renderer. Most renderers will render each each Node’s template and append them all together. In addition to the Nodes that you have defined in your subclass, a Node for the beginning and end of your Form will automatically be injected. The is a convenience that can be disabled by setting the Form.auto_start_close to False. We can see this functionality in action in the below example:

>>> form = PersonalForm()
>>> for node in form._node_list:
...     print node._attr_name
...
start
first
last
address
submit
close

Even though ‘first’ was our first element in the Form and ‘submit’ was our last, the Nodes ‘start’ and ‘close’ have been prepended and appended respectively. By default these Nodes load from templates ‘form_open.html’ and ‘form_close.html’, however these values can be easily overridden, as can the entire start and close Nodes. For more information see the Form.auto_start_close, Form.start_template, Form.close_template. Passing in a ‘start’ or ‘close’ attribute, either through keywords or subclass attributes, will override the default generated Nodes, but it will still place them at the beginning and end.

Validation Intro

To add some validation to our Form we need to create a Check. Checks are just containers for Validators and hold information about how the Validator should be executed. The below code will add a Check for the ‘first’ Node to ensure a minimum length of 5 characters.

from yota import Form
from yota.nodes import *
from yota.validation import

class PersonalForm(Form):

    first = EntryNode()
    _first_valid = Check(MinLengthValidator(5), 'first')
    last = EntryNode()
    address = EntryNode()
    submit = SubmitNode(title="Submit")

The constructor prototype may help provide some reference for the explaination:

When you define a Check object you are essentially specifying a Validator that needs to be run when the Form data is validated, and the information that needs to be passed to said Validator. Attr_args and attr_kwargs should be strings that define what data will get passed into the Validator at validation time. For instance in the above example that data that was entered for the ‘first’ Node will get passed to the validator. More information on Checks and Validators can be found on the Validators and Checks page.

Dynamic Forms

One of the key features of Yota is the ability to make changes to the Form schema at runtime with little effort. For example, say you wanted to make a Form that allowed the user to enter a list of names, and the form included a button that added another field with JavaScript. Or perhaps you would like to create a Form that is slightly different depending on session data. With a dynamic Form schema managing these situations can be much easier.

Since the Form object that is used to run validation after a submission needs to match the Form object that was used to originally render the Form there are some considerations that need to be made. There are of course many ways to try and solve this synchronization problem, but here is a straightforward solution that should apply to most situations.

This section currently needs expansion, however a thoroughly commented example can be found in the yota_examples github repository.

Form API

class yota.Form(**kwargs)[source]

This is the base class that all user defined forms should inherit from, and as such it is the main way to access functionality in Yota. It provides the core functionality involved with setting up and rendering the form.

Parameters:
  • context – This is a context specifically for the special form open and form close nodes, canonically called start and close.
  • g_context – This is a global context that will be passed to all nodes in rendering thorugh their rendering context as ‘g’ variable.
  • start_template – The template used when automatically injecting a start Node. See yota.Form.auto_start_close for more information.
  • close_template – The template used when automatically injecting a close Node. See yota.Form.auto_start_close for more information.
  • auto_start_close – Dictates whether or not start and close Nodes will be automatically appended/prepended to your form. Note that this must be set via __init__ or your class definition since it must be set before __init__ for the Form is run.
  • hidden – A dictionary of hidden key/value pairs to be injected into the form. This is frequently used to pass dynamic form parameters into the validator.
_event_lists = {}
_gen_validate(data, piecewise=False)[source]

This is an internal utility function that does the grunt work of running validation logic for a Form. It is called by the other primary validation methods.

_node_list = []
_parse_shorthand_validator(node)[source]

Loops thorugh all the Nodes and checks for shorthand validators. After inserting their checks into the form obj they are removed from the node. This is because a validation may be called multiple times on a single form instance.

_process_errors()[source]
_processor

This is a class that performs post processing on whatever is passed in as data during validation. The intended purpose of this was to write processors that translated submitted form data from the format of the web framework being used to a format that Yota expects. It also allows things like filtering stripping characters or encoding all data that enters a validator.

alias of FlaskPostProcessor

_renderer

This is a class object that is used to perform the actual rendering steps, allowing different rendering engines to be swapped out. More about this in the section Renderer

alias of JinjaRenderer

_reserved_attr_names = ('context', 'hidden', 'g_context', 'start_template', 'close_template', 'auto_start_close', '_renderer', '_processor', 'name')
_setup_node(node)[source]

An internal function performs some safety checks, sets attribute, and set_identifiers

_validation_list = []
add_listener(listener, type)[source]

Attaches a Listener to an event type. These Listener will be executed when trigger event is called.

auto_start_close = True
close_template = 'form_close'
context = {}
data_by_attr()[source]

Returns a dictionary of currently stored Node.data attributes keyed by Node._attr_name. Used for returning data after its been processed by validators.

data_by_name()[source]

Returns a dictionary of currently stored Node.data attributes keyed by Node.name. Used for returning data after its been processed by validators.

error_header_generate(errors, block)[source]

This function, along with success_header_generate allow you to give form wide information back to the user for both AJAJ validated forms and conventionally validated forms, although the mechanisms are slightly different. Both functions are run at the end of a successful or failed validation call in order to give more information for rendering.

For passing information to AJAJ rendering, simply return a dictionary, or any Python object that can be serialized to JSON. This information gets passed back to the JavaScript callbacks of yota_activate, however each in slightly different ways. success_header_generate’s information will get passed to the render_success callback, while error_header_generate will get sent as an error to the render_error callback under the context start.

For passing information into a regular, non AJAJ context simply access the attribute manually similar to below.

self.start.add_error(
    {'message': 'Please resolve the errors below to continue.'})

This will provide a simple error message to your start Node. In practice these functions could also be used to trigger events and other interesting things, although that was not their intended function.

Parameters:
  • errors – This will be a list of all other Nodes that have errors.
  • block (boolean) – Whether or not the form submission will be blocked.
g_context = {}
get_by_attr(name)[source]

Safe accessor for looking up a node by Node._attr_name

insert(position, new_node_list)[source]

Inserts a Node object or a list of objects at the specified position into the Form._node_list of the form. Index -1 is an alias for the end of the list. After insertion the Node.set_identifiers() will be called to generate identification for the Node. For this to function, Form._attr_name must be specified for the node prior to insertion.

insert_after(prev_attr_name, new_node_list)[source]

Runs through the internal node structure attempting to find a Node object whos Node._attr_name is prev_attr_name and inserts the passed node after it. If prev_attr_name cannot be matched it will be inserted at the end. Internally calls Form.insert() and has the same requirements of the Node.

Parameters:
  • prev_attr_name (string) – The attribute name of the Node that you would like to insert after.
  • new_node_list (Node or list of Nodes) – The Node or list of Nodes to be inserted.
insert_validator(new_validators)[source]

Inserts a validator to the validator list.

Parameters:validator (Check) – The Check to be inserted.
json_validate(data, piecewise=False, raw=False)[source]

The same as Form.validate_render() except the errors are loaded into a JSON string to be passed back as a query result. This output is designed to be used by the Yota Javascript library.

Parameters:
  • piecewise (boolean) – If set to True, the validator will silently ignore validator for which it has insufficient information. This is designed to be used for the AJAJ piecewise validation function, although it does not have to be.
  • raw (boolean) – If set to True then the second return parameter will be a Python dictionary instead of a JSON string
Returns:

A boolean whether or not the form submission is valid and the json string (or raw dictionary) to pass back to the javascript side. The boolean is an anding of submission (whether the submit button was actually pressed) and the block parameter (whether or not any blocking validators passed)

name = None
render()[source]

Runs the renderer to parse templates of nodes and generate the form HTML.

Returns:A string containing the generated output.
render_error = False
render_success = False
start_template = 'form_open'
success_header_generate()[source]

Please see the documentation for Form.error_header_generate() as it covers this function as well as itself.

title = None
trigger_event(type)[source]

Runs all the associated Listener‘s for a specific event type.

type_class_map = {'info': 'alert alert-info', 'warn': 'alert alert-warn', 'success': 'alert alert-success', 'error': 'alert alert-error'}

A mapping of error types to their respective class values. Used to render messages to the user from validation. Changing it to render messages differently could be performed as follows:

class MyForm(yota.Form):
    first = EntryNode(title='First name', validators=Check(MinLengthValidator(5)))
    last = EntryNode(title='Last name', validators=MinLengthValidator(5)

    # Override the default type_class_map with our own
    type_class_map = {'error': 'alert alert-error my-special-class', # Add an additional class
                    'info': 'alert alert-info',
                    'success': 'alert alert-success',
                    'warn': 'alert alert-warn'}
update_success(update_dict, raw=False)[source]

This method serves as an easy way to update your success attributes that are passed to the start Node rendering context, or passed back in JSON. It automatically recalls whether the last validation call was to json_validate or validate_render and modifys the correct dictionary accordingly.

Parameters:
  • update_dict – The dictionary of values to update/add.
  • raw (bool) – Whether you would like a pre-compiled JSON string returned, or the raw dictionary.
Returns:

Return value is either the new JSON string (or raw dict if requested) if json_validate was your last validation call, or a re-render of the form with updated error messages if validate_render was your last call.

validate(data)[source]

Runs all the validators associated with the Form.

Returns:Whether the validators are blocking submission and a list of nodes that have validation messages.
validate_render(data)[source]

Runs all the validators on the data that is passed in and returns a re-render of the Form if there are validation errors, otherwise it returns True representing a successful submission. Since validators are designed to pass error information in through the Node.errors attribute then this error information is in turn availible through the rendering context.

Parameters:data (dictionary) – The data to be passed through the Form._processor. If the data is in the form of a dictionary where the key is the ‘name’ of the form field and the data is a string then no post-processing is neccessary.
Returns:Whether the validators are blocking submission and a re-render of the form with the validation data passed in.
validator()[source]

This is provided as a convenience method for Validation logic that is one-off, and only intended for a single form. Simply override this function and access any of your Nodes and their data via the self. This method will be called after all other Validators are run.

Project Versions

Table Of Contents

Previous topic

Yota: Flexible forms with asynchronous validation

Next topic

Nodes

This Page