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='auto', internal=False, resolver=None)

Runs all the validators associated with the Form.

Returns:Whether validation was successful
_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_msgs()[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

_submit_action = False

Tracks whether you’re submitting the form, or just validating it for later json serialization

_success_data = None

Hold information that will be serialized into success return values for render_json

_validation_list = []
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(msgs)[source]

This function is generally used to generate a header on the start Node automatically when there is an error in validation. For instance, you might want to say “Please fix the errors below” or something similar. While it could actually be used for anything post-validation failure, it is better practice to create a listener that subscribes to “validation_failure” event, as this function is called at the same time.

Parameters:msgs (list) – This will be a list of all other Nodes that have messages, with the idea that you might want to list the errors that occurred.
g_context = {}
get_by_attr(name)[source]

Safe accessor for looking up a node by Node._attr_name

insert_listener(listener)[source]

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

insert_node(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_node_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.
is_piecewise()[source]
name = None
pysistor_adapter = None
pysistor_backend = None

This defines an adapter object that will be made availible to the Pysistor backend for use in storing the data. For instance, access to sessions frequently requires access to the request object and an adapter can carry that information. More information on this behaviour can be gotten in the pysistor documentation

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_json(invalid=None, success=None, raw=False)[source]

This function takes the state that is stored internally and serializes it into a form that the yota JS library is designed to recieve.

render_success = False
resolve_all(data)[source]

This is a utility method that runs resolve_data on all nodes with the provided data dictionary.

set_json_success(**kwargs)[source]

As opposed to using generate_json_success to pass information to the js success function you can use add_success in your view code.

start_template = 'form_open'
success_json_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'}
validate(data, piecewise='auto', internal=False, resolver=None)[source]

Runs all the validators associated with the Form.

Returns:Whether validation was successful
validate_json(data, piecewise='auto', raw=False)[source]

The same as Form.validate_render() except the messges 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 – This parameter is deprecated. Piecewise is automatically detected from g_context.
  • 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)

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 message, otherwise it returns True representing a successful submission. Since validators are designed to pass error information in through the Node.msgs 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 attribute. This method will be called after all other Checks are run.