Describe YAFOWIL forms with YAML#
It is possible to describe YAFOWIL forms using YAML as description language.
JSON syntax is a subset of YAML version 1.2, so we support JSON too.
Create file containing form description#
Create a file, i.e. demo_form.yaml and add widget configuration.
factory: form
name: demo_form
props:
action: context.form_action
widgets:
- title:
factory: "label:field:error:text"
value: expr:context.get('title', '')
props:
label: i18n:title:Title
required: i18n:title_required:No title given
- description:
factory: label:field:textarea
value: expr:context.get('description', '')
props:
label: i18n:description:Description
rows: 5
- save:
factory: submit
props:
action: save
expression: True
handler: context.save
next: context.next
label: i18n:save:Save
In JSON notation the same would look like this.
{
"factory": "form",
"name": "demo_form",
"props": {
"action": "context.form_action"
},
"widgets": [
{
"title": {
"factory": "label:field:error:text",
"value": "expr:context.get('title', '')",
"props": {
"label": "i18n:title:Title",
"required": "i18n:title_required:No title given"
}
}
},
{
"description": {
"factory": "label:field:textarea",
"value": "expr:context.get('description', '')",
"props": {
"label": "i18n:description:Description",
"rows": 5
}
}
},
{
"save": {
"factory": "submit",
"props": {
"action": "save",
"expression": true,
"handler": "context.save",
"label": "i18n:save:Save",
"next": "context.next"
}
}
}
]
}
Each widget node is represented by an associative array.
Keys are mapping to corresponding arguments of yafowil.base.factory
signature:
factoryChained factory registration names.
nameWidget name. Only required on root, for children widget key is used.
valueWidget value or callable/expression returning widget value.
propsWidget properties as associative array. You can prefix individual properties with the name of the blueprint to address a specific blueprint. For Example use: label.title to set the title attribute of the label.
customCustom widget properties as associative array.
modeWidget rendering mode or callable/expression returning widget rendering mode.
nestInclude other yaml/json file representing this widget.
widgetsChild widgets as list. Each child widget is an associative array with one key - the widget name - containing again an associative array with the keys descibed here.
Computed values#
Beside static values, definitions may contain python expressions, i18n message strings, access to a rendering context and pointers to callables.
i18n:If definition value starts with
i18n:, a message string gets created by calling given message factory.expr:If definition value starts with
expr:, a yafowil callback wrapper gets created, acceptingwidgetanddatakeyword arguments, which is executed when the widget tree is processed. For security reasons, only renderingcontext,widgetanddataare available in expressions.python:If definition value starts with
python:it gets evaluated as plain python expression. This is useful for the rare cases where yafowil or one of it’s addons expects a callable not acceptingwidgetanddataas arguments, likedatatypedoes. By default, these expressions get an empty globals dictionary. Python expression globals can be customized either globally by adding values toyafowil.yaml.python_expression_globalsor per parser run by passingexpression_globalstoYAMLParserconstructor respectiveparse_from_YAMLfunction. Parser specific globals take precedence over globally defined ones.contextIf definition value starts with
context, rendering context is used to lookup callbacks. If lookup fails, return definition value as string..in valueIf
.is found in value string, try to lookup callback from module path. When lookup fails, return definition value as string.
Define rendering context#
A rendering context has to be provided. Refering to the form description example above, this may look like:
>>> class FormRenderingContext(object):
...
... def get(self, key, default=None):
... # do data lookup here
... value = key
... return value
...
... def form_action(self, widget, data):
... # create and return form action URL
... return 'http://example.com/form_action'
...
... def save(self, widget, data):
... # extract and save form data
... pass
...
... def next(self, request):
... # compute and return next URL
... return 'http://example.com/form_action_succeed'
Create Message Factory#
Unless no others are registered one want to use message factories from
pyramid.i18n or zope.i18nmessageid. See refering documentation for
details. Here we create a dummy message factory:
>>> message_factory = lambda x: x
Creating YAFOWIL-Forms form YAML-Files#
To create a yafowil widget tree from YAML, use yafowil.yaml.parse_from_YAML.
This accepts also JSON file files ending with .json.
To adress a specific pyhton package path prefix the filename with
my.module::
>>> import yafowil.loader
>>> from yafowil.yaml import parse_from_YAML
>>> rendering_context = FormRenderingContext()
>>> expression_globals = {}
>>> form = parse_from_YAML(
... 'yafowil.yaml:demo_form.yaml',
... context=rendering_context,
... message_factory=message_factory,
... expression_globals=expression_globals
... )
This results into…:
>>> form.printtree()
<class 'yafowil.base.Widget'>: demo_form
<class 'yafowil.base.Widget'>: title
<class 'yafowil.base.Widget'>: description
<class 'yafowil.base.Widget'>: save
…which renders:
>>> pxml(form())
<form action="http://example.com/form_action" enctype="multipart/form-data" id="form-demo_form" method="post" novalidate="novalidate">
<label for="input-demo_form-title">Title</label>
<div class="field" id="field-demo_form-title">
<input class="required text" id="input-demo_form-title" name="demo_form.title" required="required" type="text" value="title"/>
</div>
<label for="input-demo_form-description">Description</label>
<div class="field" id="field-demo_form-description">
<textarea class="textarea" cols="80" id="input-demo_form-description" name="demo_form.description" rows="5">description</textarea>
</div>
<input id="input-demo_form-save" name="action.demo_form.save" type="submit" value="Save"/>
</form>
Manage translations of YAML forms#
As shown above, YAML forms may contain i18n translation strings. The message strings and the corresponding default values can be extracted automatically and written to po files using lingua if yafowil.lingua plugin is installed.
For details on managing translations with lingua please refer to
corresponding documentation.