:mod:`formalchemy.fields` -- `Fields` and `Renderers`
=====================================================
.. automodule:: formalchemy.fields
.. Commented imports
>>> from formalchemy.fields import *
>>> from formalchemy.tests import *
>>> from datetime import datetime
Fields
------
.. autoclass:: AbstractField
:members:
.. autoclass:: Field
:members:
.. autoclass:: AttributeField
:members:
Renderers
---------
It is important to note that althought these objects are called
`renderers`, they are also responsible for deserialization of data
received from the web and insertion of those (possibly mangled) values
back to the SQLALchemy object, if any.
They also have to take into consideration that the data used when
displaying `can` come either from the `self.params` (the dict-like
object received from the web) or from the model. The latter case
happens when first displaying a form, and the former when validation
triggered an error, and the form is to be re-displayed (and still
contain the values you entered).
FieldRenderer
*************
.. autoclass:: FieldRenderer
:members:
TextFieldRenderer
*****************
.. autoclass:: TextFieldRenderer
:members:
Render a string field::
>>> fs = FieldSet(One)
>>> fs.append(Field(name='text', type=types.String, value='a value'))
Edit mode::
>>> print(fs.text.render())
Read only mode::
>>> print(fs.text.render_readonly())
a value
IntegerFieldRenderer
********************
.. autoclass:: IntegerFieldRenderer
:members:
PasswordFieldRenderer
*********************
.. autoclass:: PasswordFieldRenderer
:members:
Render a string field::
>>> fs = FieldSet(One)
>>> fs.append(Field(name='passwd').with_renderer(PasswordFieldRenderer))
Edit mode::
>>> print(fs.passwd.render())
Read only mode::
>>> print(fs.passwd.render_readonly())
******
TextAreaFieldRenderer
*********************
.. autoclass:: TextAreaFieldRenderer
:members:
Render a string field::
>>> fs = FieldSet(One)
>>> fs.append(Field(name='text',value='a value').with_renderer(TextAreaFieldRenderer))
Edit mode::
>>> print(fs.text.render())
Read only mode::
>>> print(fs.text.render_readonly())
a value
HiddenFieldRenderer
*******************
.. autoclass:: HiddenFieldRenderer
:members:
Render a string field::
>>> fs = FieldSet(One)
>>> fs.append(Field(name='text', value='h').with_renderer(HiddenFieldRenderer))
Edit mode::
>>> print(fs.render())
Read only mode::
>>> print(fs.text.render_readonly())
HiddenFieldRendererFactory
***************************
.. autofunction:: HiddenFieldRendererFactory
CheckBoxFieldRenderer
*********************
.. autoclass:: CheckBoxFieldRenderer
:members:
FileFieldRenderer
*****************
.. autoclass:: FileFieldRenderer
:members:
DateFieldRenderer
*****************
.. autoclass:: DateFieldRenderer
:members:
Render a date field::
>>> date = datetime(2000, 12, 31, 9, 00)
>>> fs = FieldSet(One)
>>> fs.append(Field(name='date', type=types.Date, value=date))
Edit mode::
>>> print(pretty_html(fs.date.render())) #doctest: +ELLIPSIS
Read only mode::
>>> print(fs.date.render_readonly())
2000-12-31
TimeFieldRenderer
*****************
.. autoclass:: TimeFieldRenderer
:members:
Render a time field::
>>> time = datetime(2000, 12, 31, 9, 3, 30).time()
>>> fs = FieldSet(One)
>>> fs.append(Field(name='time', type=types.Time, value=time))
Edit mode::
>>> print(pretty_html(fs.time.render())) #doctest: +ELLIPSIS
:
:
Read only mode::
>>> print(fs.time.render_readonly())
09:03:30
DateTimeFieldRenderer
*********************
.. autoclass:: DateTimeFieldRenderer
:members:
Render a datetime field::
>>> datetime = datetime(2000, 12, 31, 9, 3, 30)
>>> fs = FieldSet(One)
>>> fs.append(Field(name='datetime', type=types.DateTime, value=datetime))
Edit mode::
>>> print(pretty_html(fs.datetime.render())) #doctest: +ELLIPSIS
:
:
Read only mode::
>>> print(fs.datetime.render_readonly())
2000-12-31 09:03:30
HiddenDateFieldRenderer
***********************
.. autoclass:: HiddenDateFieldRenderer
HiddenTimeFieldRenderer
***********************
.. autoclass:: HiddenTimeFieldRenderer
HiddenDateTimeFieldRenderer
***************************
.. autoclass:: HiddenDateTimeFieldRenderer
RadioSet
********
.. autoclass:: RadioSet
:members:
CheckBoxSet
***********
.. autoclass:: CheckBoxSet
:members:
SelectFieldRenderer
*******************
.. autoclass:: SelectFieldRenderer
:members:
EscapingReadonlyRenderer
************************
.. autoclass:: EscapingReadonlyRenderer
:members:
Custom renderer
---------------
You can write your own `FieldRenderer` s to customize the widget (input
element[s]) used to edit different types of fields...
1. Subclass `FieldRenderer`.
1. Override `render` to return a string containing the HTML input
elements desired. Use `self.name` to get a unique name and id for the
input element. `self._value` may also be useful if you are not
rendering multiple input elements.
2. If you are rendering a custom type (any class you defined yourself),
you will need to override `deserialize` as well. `render` turns the
user-submitted data into a Python value. (The raw data will be
available in self.field.parent.data, or you can use
`_serialized_value` if it is convenient.) For SQLAlchemy collections,
return a list of primary keys, and `FormAlchemy` will take care of
turning that into a list of objects. For manually added collections,
return a list of values.
3. If you are rendering a builtin type with multiple input elements,
override `_serialized_value` to return a single string combining the
multiple input pieces. See the source for DateFieldRenderer for an
example.
2. Update `FieldSet.default_renderers`. `default_renderers` is a dict of
FieldRenderer subclasses. The default contents of
`default_renderers` is::
.. literalinclude:: ../formalchemy/forms.py
:pyobject: DefaultRenderers
For instance, to make `Boolean` s render as select fields with Yes/No
options by default, you could write::
>>> from formalchemy.fields import SelectFieldRenderer
>>> class BooleanSelectRenderer(SelectFieldRenderer):
... def render(self, **kwargs):
... kwargs['options'] = [('Yes', True), ('No', False)]
... return SelectFieldRenderer.render(self, **kwargs)
>>> FieldSet.default_renderers[types.Boolean] = BooleanSelectRenderer
Of course, you can subclass `FieldSet` if you don't want to change the defaults globally.
One more example, this one to use the
`JQuery UI DatePicker `_
to render `Date` objects::
>>> from formalchemy.fields import FieldRenderer
>>> class DatePickerFieldRenderer(FieldRenderer):
... def render(self):
... value= self.value and self.value or ''
... vars = dict(name=self.name, value=value)
... return """
...
...
... """ % vars
(Obviously the page template will need to add references to the jquery library
and css.)
Another example to render a link field::
>>> class LinkFieldRenderer(FieldRenderer):
... def render(self, **kwargs):
... """render html for edit mode"""
... from formalchemy import helpers as h
... return h.text_field(self.name, value=self._value, **kwargs)
... def render_readonly(self, **kwargs):
... """render html for read only mode"""
... kwargs = {'value':self.field.raw_value}
... return '%(value)s' % kwargs
Then bind it to a specific field::
>>> from formalchemy.tests import *
>>> fs = FieldSet(One)
>>> fs.append(Field('link', value='http://www.formalchemy.org'))
>>> fs.configure(include=[fs.link.with_renderer(LinkFieldRenderer)])
Here is the result for edit mode::
>>> print(fs.render())
And for read only mode::
>>> fs.readonly = True
>>> print(fs.render())