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

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 by iterating the collection (for row in collection). Alternately, you can call _set_active(row).

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:

>>> from formalchemy.helpers import literal
>>> tc2 = Grid(User, [bill, john])
>>> tc2.append(Field('link', type=types.String, value=lambda item: literal('<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()