: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()) Link: http://www.formalchemy.org