formalchemy.fieldsFields and Renderers

Fields

class formalchemy.fields.AbstractField(parent)

Contains the information necessary to render (and modify the rendering of) a form field

Methods taking an options parameter will accept several ways of specifying those options:

  • an iterable of SQLAlchemy objects; str() of each object will be the description, and the primary key the value
  • a SQLAlchemy query; the query will be executed with all() and the objects returned evaluated as above
  • an iterable of (description, value) pairs
  • a dictionary of {description: value} pairs

Options can be “chained” indefinitely because each modification returns a new Field instance, so you can write:

>>> from formalchemy.tests import FieldSet, User
>>> fs = FieldSet(User)
>>> fs.append(Field('foo').dropdown(options=[('one', 1), ('two', 2)]).radio())

or:

>>> fs.configure(options=[fs.name.label('Username').readonly()])
bind(parent)
Return a copy of this Field, bound to a different parent
checkbox(options=None)
Render the field as a set of checkboxes.
dropdown(options=None, multiple=False, size=5)
Render the field as an HTML select field. (With the multiple option this is not really a ‘dropdown’.)
hidden()
Render the field hidden. (Value only, no label.)
is_readonly()
True iff this Field is in readonly mode
is_required()
True iff this Field must be given a non-empty value
label(text)
Change the label associated with this field. By default, the field name is used, modified for readability (e.g., ‘user_name’ -> ‘User name’).
model_value
raw value from model, transformed if necessary for use as a form input value.
password()
Render the field as a password input, hiding its value.
query(*args, **kwargs)
Perform a query in the parent’s session
radio(options=None)
Render the field as a set of radio buttons.
raw_value()
raw value from model. different from .model_value in SQLAlchemy fields, because for reference types, .model_value will return the foreign key ID. This will return the actual object referenced instead.
readonly(value=True)
Render the field readonly.
render()
Render this Field as HTML.
render_readonly()
Render this Field as HTML for read only mode.
required()
Convenience method for validate(validators.required). By default, NOT NULL columns are required. You can only add required-ness, not remove it.
reset()
Return the field with all configuration changes reverted.
set(**kwattrs)

Update field attributes in place. Allowed attributes are: validate, renderer, required, readonly, nul_as, label, multiple, options, size, instructions, metadata:

>>> field = Field('myfield')
>>> field.set(label='My field', renderer=SelectFieldRenderer,
...            options=[('Value', 1)])
AttributeField(myfield)
>>> field.label_text
'My field'
>>> field.renderer
<SelectFieldRenderer for AttributeField(myfield)>
textarea(size=None)
Render the field as a textarea. Size must be a string (“25x10”) or tuple (25, 10).
validate(validator)
Add the validator function to the list of validation routines to run when the FieldSet‘s validate method is run. Validator functions take one parameter: the value to validate. This value will have already been turned into the appropriate data type for the given Field (string, int, float, etc.). It should raise ValidationError if validation fails with a message explaining the cause of failure.
value

The value of this Field: use the corresponding value in the bound data, if any; otherwise, use the value in the bound model. For SQLAlchemy models, if there is still no value, use the default defined on the corresponding Column.

For SQLAlchemy collections, a list of the primary key values of the items in the collection is returned.

Invalid form data will cause an error to be raised. Controllers should thus validate first. Renderers should thus never access .value; use .model_value instead.

with_html(**html_options)

Give some HTML options to renderer.

Trailing underscore (_) characters will be stripped. For example, you might want to add a class attribute to your checkbox. You would need to specify .options(class_=’someclass’).

For WebHelpers-aware people: those parameters will be passed to the text_area(), password(), text(), etc.. webhelpers.

NOTE: Those options can override generated attributes and can mess
the sync calls, or label-tag associations (if you change name, or id for example). Use with caution.
with_metadata(**attrs)

Attach some metadata attributes to the Field, to be used by conditions in templates.

Example usage:

>>> test = Field('test')
>>> field = test.with_metadata(instructions='use this widget this way')
...

And further in your templates you can verify:

>>> 'instructions' in field.metadata
True

and display the content in a <span> or something.

with_null_as(option)
Render null as the given option tuple of text, value.
with_renderer(renderer)
Return a copy of this Field, with a different renderer. Used for one-off renderer changes; if you want to change the renderer for all instances of a Field type, modify FieldSet.default_renderers instead.
class formalchemy.fields.Field(name=None, type=<class 'sqlalchemy.types.String'>, value=None, **kwattrs)

A manually-added form field

Create a new Field object.

  • name:

    field name

  • type=types.String:

    data type, from formalchemy.types (Integer, Float, String, Binary, Boolean, Date, DateTime, Time) or a custom type

  • value=None:

    default value. If value is a callable, it will be passed the current bound model instance when the value is read. This allows creating a Field whose value depends on the model once, then binding different instances to it later.

    • name: field name
    • type: data type, from formalchemy.types (Boolean, Integer, String, etc.), or a custom type for which you have added a renderer.
    • value: default value. If value is a callable, it will be passed the current bound model instance when the value is read. This allows creating a Field whose value depends on the model once, then binding different instances to it later.
sync()
Set the attribute’s value in model to the value given in data
class formalchemy.fields.AttributeField(instrumented_attribute, parent)

Field corresponding to an SQLAlchemy attribute.

>>> from formalchemy.tests import FieldSet, Order
>>> fs = FieldSet(Order)
>>> print fs.user.key
user
>>> print fs.user.name
user_id
relation_type()
The type of object in the collection (e.g., User). Calling this is only valid when is_relation is True.
sync()
Set the attribute’s value in model to the value given in data

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

class formalchemy.fields.FieldRenderer(field)

This should be the super class of all Renderer classes.

Renderers generate the html corresponding to a single Field, and are also responsible for deserializing form data into Python objects.

Subclasses should override render and deserialize. See their docstrings for details.

deserialize()

Turns the user-submitted data into a Python value.

The raw data received from the web can be accessed via self.params. This dict-like object usually accepts the getone() and getall() method calls.

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.

You will need to override this in a child Renderer object if you want to mangle the data from your web form, before it reaches your database model. For example, if your render() method displays a select box filled with items you got from a CSV file or another source, you will need to decide what to do with those values when it’s time to save them to the database – or is this field going to determine the hashing algorithm for your password ?.

This function should return the value that is going to be assigned to the model and used in the place of the model value if there was an error with the form.

Note

Note that this function will be called twice, once when the fieldset is .validate()‘d – with it’s value only tested, and a second time when the fieldset is .sync()‘d – and it’s value assigned to the model. Also note that deserialize() can also raise a ValidationError() exception if it finds some errors converting it’s values.

If calling this function twice poses a problem to your logic, for example, if you have heavy database queries, or temporary objects created in this function, consider using the deserialize_once decorator, provided using:

from formalchemy.fields import deserialize_once

@deserialize_once
def deserialize(self):
    ... my stuff ...
    return calculated_only_once

Finally, you should only have to override this if you are using custom (e.g., Composite) types.

errors
Return the errors on the FieldSet if any. Useful to know if you’re redisplaying a form, or showing up a fresh one.
get_translator(**kwargs)
return a GNUTranslations object in the most convenient way
name

Name of rendered input element.

The name of a field will always look like:
[fieldset_prefix-]ModelName-[pk]-fieldname

The fieldset_prefix is defined when instantiating the FieldSet object, by passing the prefix= keyword argument.

The ModelName is taken by introspection from the model passed in at that same moment.

The pk is the primary key of the object being edited. If you are creating a new object, then the pk is an empty string.

The fieldname is, well, the field name.

Note

This method as the direct consequence that you can not create two objects of the same class, using the same FieldSet, on the same page. You can however, create more than one object of a certain class, provided that you create multiple FieldSet instances and pass the prefix= keyword argument.

Otherwise, FormAlchemy deals very well with editing multiple existing objects of same/different types on the same page, without any name clash. Just be careful with multiple object creation.

When creating your own Renderer objects, use self.name to get the field’s name HTML attribute, both when rendering and deserializing.

params

This gives access to the POSTed data, as received from the web user. You should call .getone, or .getall to retrieve a single value or multiple values for a given key.

For example, when coding a renderer, you’d use:

vals = self.params.getall(self.name)

to catch all the values for the renderer’s form entry.

raw_value
return fields field.raw_value (mean real objects, not ForeignKeys)
render(**kwargs)

Render the field. Use self.name to get a unique name for the input element and id. self.value may also be useful if you are not rendering multiple input elements.

When rendering, you can verify self.errors to know if you are rendering a new form, or re-displaying a form with errors. Knowing that, you could select the data either from the model, or the web form submission.

render_readonly(**kwargs)
render a string representation of the field value
value
Submitted value, or field value converted to string. Return value is always either None or a string.

TextFieldRenderer

class formalchemy.fields.TextFieldRenderer(field)
render a field as a text field

Render a string field:

>>> fs = FieldSet(One)
>>> fs.append(Field(name='text', type=types.String, value='a value'))

Edit mode:

>>> print fs.text.render()
<input id="One--text" name="One--text" type="text" value="a value" />

Read only mode:

>>> print fs.text.render_readonly()
a value

IntegerFieldRenderer

class formalchemy.fields.IntegerFieldRenderer(field)
render an integer as a text field

PasswordFieldRenderer

class formalchemy.fields.PasswordFieldRenderer(field)
Render a password field

Render a string field:

>>> fs = FieldSet(One)
>>> fs.append(Field(name='passwd').with_renderer(PasswordFieldRenderer))

Edit mode:

>>> print fs.passwd.render()
<input id="One--passwd" name="One--passwd" type="password" />

Read only mode:

>>> print fs.passwd.render_readonly()
******

TextAreaFieldRenderer

class formalchemy.fields.TextAreaFieldRenderer(field)
render a field as a textarea

Render a string field:

>>> fs = FieldSet(One)
>>> fs.append(Field(name='text',value='a value').with_renderer(TextAreaFieldRenderer))

Edit mode:

>>> print fs.text.render()
<textarea id="One--text" name="One--text">a value</textarea>

Read only mode:

>>> print fs.text.render_readonly()
a value

HiddenFieldRenderer

class formalchemy.fields.HiddenFieldRenderer(field)
render a field as an hidden field

Render a string field:

>>> fs = FieldSet(One)
>>> fs.append(Field(name='text', value='h').with_renderer(HiddenFieldRenderer))

Edit mode:

>>> print fs.render()
<input id="One--text" name="One--text" type="hidden" value="h" />

Read only mode:

>>> print fs.text.render_readonly()
<BLANKLINE>

CheckBoxFieldRenderer

class formalchemy.fields.CheckBoxFieldRenderer(field)
render a boolean value as checkbox field

FileFieldRenderer

class formalchemy.fields.FileFieldRenderer(*args, **kwargs)

render a file input field

render_readonly(**kwargs)
render only the binary size in a human readable format but you can override it to whatever you want

DateFieldRenderer

class formalchemy.fields.DateFieldRenderer(field)
Render a date field

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
<span id="One--date">
 <select id="One--date__month" name="One--date__month">
  <option value="MM">
   Month
  </option>
  <option value="1">
   January
  </option>
...
  <option selected="selected" value="12">
   December
  </option>
 </select>
 <select id="One--date__day" name="One--date__day">
  <option value="DD">
   Day
  </option>
  <option value="1">
   1
  </option>
...
  <option selected="selected" value="31">
   31
  </option>
 </select>
 <input id="One--date__year" maxlength="4" name="One--date__year" size="4" type="text" value="2000" />
</span>

Read only mode:

>>> print fs.date.render_readonly()
2000-12-31
class formalchemy.fields.TimeFieldRenderer(field)
Render a time field

Render a time field:

>>> time = datetime(2000, 12, 31, 9, 03, 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
<span id="One--time">
 <select id="One--time__hour" name="One--time__hour">
  <option value="HH">
   HH
  </option>
  <option value="0">
   0
  </option>
...
  <option selected="selected" value="9">
   9
  </option>
...
  <option value="23">
   23
  </option>
 </select>
 :
 <select id="One--time__minute" name="One--time__minute">
  <option value="MM">
   MM
  </option>
  <option value="0">
   0
  </option>
...
  <option selected="selected" value="3">
   3
  </option>
...
  <option value="59">
   59
  </option>
 </select>
 :
 <select id="One--time__second" name="One--time__second">
  <option value="SS">
   SS
  </option>
  <option value="0">
   0
  </option>
...
  <option selected="selected" value="30">
   30
  </option>
...
  <option value="59">
   59
  </option>
 </select>
</span>

Read only mode:

>>> print fs.time.render_readonly()
09:03:30

DateTimeFieldRenderer

class formalchemy.fields.DateTimeFieldRenderer(field)
Render a date time field

Render a datetime field:

>>> datetime = datetime(2000, 12, 31, 9, 03, 30)
>>> fs = FieldSet(One)
>>> fs.append(Field(name='datetime', type=types.DateTime, value=datetime))

Edit mode:

>>> print pretty_html(fs.datetime.render())  #doctest: +ELLIPSIS
<span id="One--datetime">
 <select id="One--datetime__month" name="One--datetime__month">
  <option value="MM">
   Month
  </option>
...
  <option selected="selected" value="12">
   December
  </option>
 </select>
 <select id="One--datetime__day" name="One--datetime__day">
  <option value="DD">
   Day
  </option>
...
  <option selected="selected" value="31">
   31
  </option>
 </select>
 <input id="One--datetime__year" maxlength="4" name="One--datetime__year" size="4" type="text" value="2000" />
 <select id="One--datetime__hour" name="One--datetime__hour">
  <option value="HH">
   HH
  </option>
...
  <option selected="selected" value="9">
   9
  </option>
...
 </select>
 :
 <select id="One--datetime__minute" name="One--datetime__minute">
  <option value="MM">
   MM
  </option>
...
  <option selected="selected" value="3">
   3
  </option>
...
 </select>
 :
 <select id="One--datetime__second" name="One--datetime__second">
  <option value="SS">
   SS
  </option>
...
  <option selected="selected" value="30">
   30
  </option>
...
 </select>
</span>

Read only mode:

>>> print fs.datetime.render_readonly()
2000-12-31 09:03:30

RadioSet

class formalchemy.fields.RadioSet(field)
render a field as radio

CheckBoxSet

class formalchemy.fields.CheckBoxSet(field)
static widget(name, value='1', checked=False, **options)
Creates a check box.

SelectFieldRenderer

class formalchemy.fields.SelectFieldRenderer(field)

render a field as select

render_readonly(options=None, **kwargs)
render a string representation of the field value. Try to retrieve a value from options

EscapingReadonlyRenderer

class formalchemy.fields.EscapingReadonlyRenderer(field)
In readonly mode, html-escapes the output of the default renderer for this field type. (Escaping is not performed by default because it is sometimes useful to have the renderer include raw html in its output. The FormAlchemy admin app extension for Pylons uses this, for instance.)

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:
class EditableRenderer(ModelRenderer):
    default_renderers = {
        fatypes.String: fields.TextFieldRenderer,
        fatypes.Unicode: fields.TextFieldRenderer,
        fatypes.Text: fields.TextFieldRenderer,
        fatypes.Integer: fields.IntegerFieldRenderer,
        fatypes.Float: fields.FloatFieldRenderer,
        fatypes.Numeric: fields.FloatFieldRenderer,
        fatypes.Interval: fields.IntervalFieldRenderer,
        fatypes.Boolean: fields.CheckBoxFieldRenderer,
        fatypes.DateTime: fields.DateTimeFieldRenderer,
        fatypes.Date: fields.DateFieldRenderer,
        fatypes.Time: fields.TimeFieldRenderer,
        fatypes.Binary: fields.FileFieldRenderer,
        fatypes.List: fields.SelectFieldRenderer,
        fatypes.Set: fields.SelectFieldRenderer,
        'dropdown': fields.SelectFieldRenderer,
        'checkbox': fields.CheckBoxSet,
        'radio': fields.RadioSet,
        'password': fields.PasswordFieldRenderer,
        'textarea': fields.TextAreaFieldRenderer,
    }

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 """
...            <input id="%(name)s" name="%(name)s"
...                   type="text" value="%(value)s">
...            <script type="text/javascript">
...              $('#%(name)s').datepicker({dateFormat: 'yy-mm-dd'})
...            </script>
...         """ % 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 '<a href="%(value)s">%(value)s</a>' % 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()
<div>
 <label class="field_opt" for="One--link">
  Link
 </label>
 <input id="One--link" name="One--link" type="text" value="http://www.formalchemy.org" />
</div>
<script type="text/javascript">
 //<![CDATA[
document.getElementById("One--link").focus();
//]]>
</script>

And for read only mode:

>>> fs.readonly = True
>>> print fs.render()
<tbody>
 <tr>
  <td class="field_readonly">
   Link:
  </td>
  <td>
   <a href="http://www.formalchemy.org">
    http://www.formalchemy.org
   </a>
  </td>
 </tr>
</tbody>