Hello,
I wrote a version of DataGrid that supports "dynamic" columns, e.g. a column
which value depends on the current row being processed. I wonder if it's useful
enough to be shared and may be integrated with stock DataGrid (it is fully
backward compatible).
# Usage is like this:
grid = DataGrid(fields=['userId', ('Homepage', get_user_home_url)])
there is tuple instead of plain string; the second arg is callable which is
called for each raw (sql object). E.g:
def get_user_home_url(user):
from kid.pull import XML
s = '<a href="%s">%s</a>' % (user.url, user.url)
return XML(s)
Here is implementation:
(the template is the same, the only difference is ${widget.getcol(row, col)}
instead of getattr)
class DataGrid(widgets.Widget):
"""Presents a grid with add/edit/delete controls based on a
SelectResults object."""
css=[widgets.CSSLink(widgets.static, "grid.css")]
template = """
<div xmlns:py="http://purl.org/kid/ns#">
<table id="${widget.name}" class="grid" cellpadding="0" cellspacing="1"
border="0">
<thead py:if="headers">
<td> </td>
<td py:for="head in headers">
${head}
</td>
</thead>
<tr py:for="i, row in enumerate(widget_value)" class="${i%2 and 'odd'
or 'even'}">
<td>
<a href="${std.url([str(row.id), 'edit'])}">
<img src="${std.tg_static}/images/edit.png" border="0"/>
</a>
<a href="${std.url([str(row.id), 'delete'])}">
<img src="${std.tg_static}/images/discard.png" border="0"/>
</a>
</td>
<td py:for="col in collist">
${widget.getcol(row, col)}
</td>
</tr>
</table>
<p><a href="add" style="text-decoration:none"><img
src="${std.tg_static}/images/add.png" border="0"/> Add a record</a></p>
</div>
"""
def __init__(self, fields=None, **kw):
super(DataGrid, self).__init__(**kw)
self.fields = fields
self.dynfields = {}
self.collist = []
def getcol(self, row, col):
if col in self.dynfields:
return self.dynfields[col](row)
return getattr(row, col)
def update_dict(self, d):
"Sets up headers based on the select results columns"
value = d["widget_value"]
cols = value.sourceClass.sqlmeta.columns
collist_raw = d.get('fields') or self.fields or list(cols.keys())
headers = []
collist = []
for name in collist_raw:
if not isinstance(name, tuple):
column = cols[name]
header = column.title or column.name.capitalize()
else:
header, f = name
self.dynfields[header] = f
name = header # to be able to key dynfields dict
headers.append(header)
collist.append(name)
d.update(dict(headers=headers, collist=collist))