formalchemy.tablesGrid: Rendering collections

Besides FieldSet, FormAlchemy provides Grid for editing and rendering multiple instances at once. Most of what you know about FieldSet applies to Grid, with the following differences to accomodate being bound to multiple objects:

The Grid class

class formalchemy.tables.Grid(cls, instances=[], session=None, data=None, request=None, prefix=None)

Besides FieldSet, FormAlchemy provides Grid for editing and rendering multiple instances at once. Most of what you know about FieldSet applies to Grid, with the following differences to accomodate being bound to multiple objects:

The Grid constructor takes the following arguments:

  • cls: the class type that the Grid will render (NOT an instance)
  • instances=[]: the instances to render as grid rows
  • session=None: as in FieldSet
  • data=None: as in FieldSet
  • request=None: as in FieldSet

bind and rebind take the last 3 arguments (instances, session, and data); you may not specify a different class type than the one given to the constructor.

The Grid errors attribute is a dictionary keyed by bound instance, whose value is similar to the errors from a FieldSet, that is, a dictionary whose keys are Field`s, and whose values are `ValidationError instances.

bind(instances, session=None, data=None, request=None)

bind to instances

configure(**kwargs)

The Grid configure method takes the same arguments as FieldSet (pk, exclude, include, options, readonly), except there is no focus argument.

copy(*args)

return a copy of the fieldset. args is a list of field names or field objects to render in the new fieldset

rebind(instances=None, session=None, data=None, request=None)

rebind to instances

sync()

These are the same as in FieldSet

sync_one(row)

Use to sync a single one of the instances that are bound to the Grid.

validate()

These are the same as in FieldSet

Creating

The Grid constructor takes parameters (cls, instances=[], session=None, data=None). A significant difference from FieldSet is that the first argument must _always_ be a mapped class, e.g., User. instances is the objects to render, which must all be of the given type. The other parameters are the same as in FieldSet.

Binding

Grid bind and rebind methods are similar to those methods in FieldSet, except they take an iterable instances instead of an instance model. Thus, the full signature is (instances, session=None, data=None).

Configuration

The Grid configure method takes the same arguments as FieldSet (pk, exclude, include, options, readonly), except there is no focus argument.

Validation and Sync

These are the same as in FieldSet, except that you can also call sync_one(instance) to sync a single one of the instances that are bound to the Grid.

The Grid errors attribute is a dictionary keyed by bound instance, whose value is similar to the errors from a FieldSet, that is, a dictionary whose keys are Field`s, and whose values are `ValidationError instances.

Customizing Grid

Overriding Grid rendering is similar to FieldSet. The differences are:

  • The default templates take a collection parameter instead of fieldset, which is the instance of Grid to render
  • The instances given to the collection are available in collection.rows; to access the fields of each single row, call _set_active(row), then access render_fields.

The default templates are formalchemy.tables.template_grid_readonly and formalchemy.tables.template_grid.

Usage

You need some imports:

>>> from formalchemy.tables import *

Then you can initialize a Grid and bind it to a list of row instance:

>>> tc = Grid(User, [bill])
>>> tc.configure(readonly=True)

This will render instances as an html table:

>>> print tc.render()
<thead>
 <tr>
  <th>
   Email
  </th>
  <th>
   Password
  </th>
  <th>
   Name
  </th>
  <th>
   Orders
  </th>
 </tr>
</thead>
<tbody>
 <tr class="even">
  <td>
   bill@example.com
  </td>
  <td>
   1234
  </td>
  <td>
   Bill
  </td>
  <td>
   Quantity: 10
  </td>
 </tr>
</tbody>

You can also add a field to the Grid manually:

>>> tc2 = Grid(User, [bill, john])
>>> tc2.append(Field('link', type=types.String, value=lambda item: '<a href=%d>link</a>' % item.id))
>>> tc2.configure(readonly=True)
>>> print tc2.render()
<thead>
 <tr>
  <th>
   Email
  </th>
  <th>
   Password
  </th>
  <th>
   Name
  </th>
  <th>
   Orders
  </th>
  <th>
   Link
  </th>
 </tr>
</thead>
<tbody>
 <tr class="even">
  <td>
   bill@example.com
  </td>
  <td>
   1234
  </td>
  <td>
   Bill
  </td>
  <td>
   Quantity: 10
  </td>
  <td>
   <a href="1">
    link
   </a>
  </td>
 </tr>
 <tr class="odd">
  <td>
   john@example.com
  </td>
  <td>
   5678
  </td>
  <td>
   John
  </td>
  <td>
   Quantity: 5, Quantity: 6
  </td>
  <td>
   <a href="2">
    link
   </a>
  </td>
 </tr>
</tbody>

You can provide a dict as new values:

>>> g = Grid(User, [bill, john], data={'User-1-email': 'bill_@example.com', 'User-1-password': '1234_', 'User-1-name': 'Bill_', 'User-1-orders': '1', 'User-2-email': 'john_@example.com', 'User-2-password': '5678_', 'User-2-name': 'John_', 'User-2-orders': ['2', '3'], })

Validation work like Fieldset:

>>> g.validate()
True

Sync too:

>>> g.sync()
>>> session.flush()
>>> session.refresh(john)
>>> john.email == 'john_@example.com'
True
>>> session.rollback()