Rendering forms and fields¶
Most of the time you’ll be using morf to display, validate and process web forms.
The class HTMLForm
provides shortcuts for this.
Most of the time it’s convenient to create forms by subclassing this.
Basic rendering¶
Forms, by default, do not know anything about HTML. For that you need a
morf.render.FormRenderer
object. There are various flavours of
FormRenderer that render in different HTML markup styles. The easiest way to get
hold of a FormRenderer
object
is to use one of the .as_*
methods on HTMLForm
:
from morf import HTMLForm, fields
class MyForm(HTMLForm):
email = fields.Str()
name = fields.Str()
form = MyForm()
print(form.as_p())
Which outputs the rendered HTML:
<p><label for="field_email-0">Email</label><div class="control"><input id="field_email-0" name="email" required="" type="text" value="" /></div></p>...
Customizing rendering templates¶
You can customize the HTML generated by calling
renderer()
:
from markupsafe import Markup
renderer = form.renderer(
form_template='<ul class="custom-form">{{ fields|join() }}</ul>',
row_template='<li class="custom-form-row">{{ field }}</li>',
field_template='<span>{{ label }}: {{ control }}</span>{{ errors }}',
errors_template=
'<div class="oops-errors">'
'{% for message in errors %}{{ message|e }}{% endfor %}'
'</div>',
label_template='<label for="{{ id }}">{{ label|e }}</label>')
print(renderer)
Which will output the HTML:
<ul class="custom-form"><li class="custom-form-row"><span><label...
The various ‘_template’ arguments are Jinja2 templates,
and you can use all of the templating features of Jinja2
to customize the output.
For example, if you wanted to add
a Django forms style help_text
attribute:
email = fields.Str(
help_text='We will send a confirmation email to this address')
renderer = form.as_p(field_template=
'<span>{{ label }}: {{ control }}</span>{{ errors }}'
'{% if 'help_text' in field.options %}
'{{ field.options.help_text|e }}'
'{% endif %}')
For more examples, take a few minutes to look at the source code of
morf.htmlform.HTMLForm
and morf.render.RenderOptions
.
Rendering individual fields¶
FormRenderer
objects know which fields have already been
rendered and which have not.
This lets you tailor rendering for selected fields while leaving morf to do the grunt work on the remaining fields. For example, here’s some sample form rendering code in a Jinja2 template:
<div class="column">
{{ form.pop('username').render(class_='MyCustomCSSClass') }}
{% for field in form.select(['email', 'password', 'password_confirm') %}
{{ field }}
{% endfor %}
</div>
<div class="column">
{% for field in form %}
{{ field }}
{% endfor %}
</div>
This template renders the form in two separate <div>
elements.
The second <div>
element will only contain fields not previously rendered
in the first <div>
element. Methods such as
morf.render.FormRenderer.pop()
,
morf.render.FormRenderer.select()
,
morf.render.FormRenderer.select_to()
,
morf.render.FormRenderer.select_match()
and morf.render.FormRenderer.select_except()
give you a lot of flexibility to slice and dice the layout of fields
within the form, without having to hand code everything.
- class morf.htmlform.HTMLForm(raw=None, bind=None, **kwargs)¶
Convenience subclass of form that also implements FormRenderer
- bind_input(raw, *args, **kwargs)¶
Bind the raw submitted value to the field
Field.extract_raw can be used to extract the raw value in the correct format for this method.
- render_with¶
alias of
morf.render.FormRenderer
- renderer(**kwargs)¶
Return a configured FormRenderer instance
- class morf.render.FieldRenderer(field, render_options, parent=None)¶
- extract_raw(raw)¶
Extract the raw value for the field from the submitted input values.
This method is in the Renderer, because it is possible for a field to be rendered using a widget that splits the value into multiple inputs (eg a time represented as separate ‘hh’ and ‘mm’ inputs)
- get_id()¶
Return a unique id, used as the basis for HTML id attributes.
The id number is incremented with each call. This is so that if the field is part of a list widget then each iteration will produce a unique id.
The id number must be a stable series. If the user wishes to script the form using javascript, having stable html ids is essential.
- property is_visible¶
bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
- class morf.render.FormRenderer(*args, **kwargs)¶
Renderer for a
Form
object.Return a copy of the
FormRenderer
object limited to displaying only hidden fields.
- pop(fieldname, default=[])¶
Return the named field, removing it from the internal list of fields to render.
- select(fields, strict=False)¶
Return an iterator over just the named fields.
The fields will be removed from the internal of fields to render so that subsequent iteration over the FormRenderer object will not return them a second time.
- select_match(match)¶
Select all fields matching the regular expression
match
. The regular expressionsearch
method is used, so match will match any part of the fieldname by default, eg:select_match('address')
would match bothaddress_1
andbilling_address1
.See
select()
for more information.
- select_to(field)¶
Select all fields up to (but not including) the named field. See
select()
for more information.
- visible()¶
Return a copy of the
FormRenderer
object limited to displaying only the visible fields.
- class morf.render.HiddenRenderer(field, render_options, parent=None)¶
Renders an <input type=”hidden”> element with no other output. Used by
Hidden
- class morf.render.ListRenderer(field, render_options, parent=None)¶
- extract_raw(raw)¶
Extract the raw value for the field from the submitted input values.
This method is in the Renderer, because it is possible for a field to be rendered using a widget that splits the value into multiple inputs (eg a time represented as separate ‘hh’ and ‘mm’ inputs)
- property is_visible¶
bool(x) -> bool
Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.
- class morf.render.NullRenderer(field, render_options, parent=None)¶
Produces no output when rendered. Used by
Constant
- class morf.render.RenderOptions(form=None, **kwargs)¶
Set of commonly tweaked parameters for rendering forms and fields
- class morf.render.Renderer(field, render_options, parent=None)¶
Renders something, eg a widget, a field or an entire form.
- copy()¶
Return a copy of the Renderer object.
All top-level attributes (including mutable structures such as processors and validators) are independently copied.
- extract_raw(raw)¶
Extract the raw value for the field from the submitted input values.
This method is in the Renderer, because it is possible for a field to be rendered using a widget that splits the value into multiple inputs (eg a time represented as separate ‘hh’ and ‘mm’ inputs)