in fact, when using model forms, this new behavior will be in the way, since when used with foreignkeys, we would have to map r.column.id to fk.id and r.column.value to fk, so that r.column.value.id == r.column.id; all that is completely unnecessary.
we're commiting this anyway to log it, but will revert right afterwards
countries = CountryTable([{'name': 'Germany', population: 80},\r
{'name': 'France', population: 64}])\r
\r
-Decide how you the table should be sorted:\r
+Decide how the table should be sorted:\r
\r
countries.order_by = ('name',)\r
assert [row.name for row in countries.row] == ['France', 'Germany']\r
{{ table.columns.tz }}\r
{% endfor %}\r
\r
+\r
ModelTables\r
-----------\r
\r
Setting ``sortable`` to False will result in this column being unusable\r
in ordering.\r
\r
+ The ``choices`` argument currently expects a boolean value (defaults to\r
+ False). If enabled, the column will be able to hold an id/value pair.\r
+ more extensive choices support (mapping an id to predefined value) is\r
+ forthcoming.\r
+\r
``django_tables.columns`` currently defines three classes, ``Column``,\r
``TextColumn`` and ``NumberColumn``. However, the two subclasses currently\r
don't do anything special at all, so you can simply use the base class.\r
\r
Setting ``sortable`` to False will result in this column being unusable\r
in ordering.\r
+\r
+ The ``choices`` argument currently expects a boolean value (defaults to\r
+ False). If enabled, the column will be able to hold an id/value pair.\r
"""\r
# Tracks each time a Column instance is created. Used to retain order.\r
creation_counter = 0\r
\r
def __init__(self, verbose_name=None, name=None, default=None,\r
- visible=True, inaccessible=False, sortable=True):\r
+ visible=True, inaccessible=False, sortable=True,\r
+ choices=None):\r
self.verbose_name = verbose_name\r
self.name = name\r
self.default = default\r
self.visible = visible\r
self.inaccessible = inaccessible\r
self.sortable = sortable\r
+ self.choices = choices\r
\r
self.creation_counter = Column.creation_counter\r
Column.creation_counter += 1\r
def __getitem__(self, name):\r
"""Returns this row's value for a column. All other access methods,\r
e.g. __iter__, lead ultimately to this."""\r
- return self.data[self.table.columns[name].declared_name]\r
+ column = self.table.columns[name]\r
+ return RowValue(self.data[column.declared_name], column)\r
\r
def __contains__(self, item):\r
"""Check by both row object and column name."""\r
values = property(_get_values)\r
\r
def as_html(self):\r
- pass
\ No newline at end of file
+ pass\r
+\r
+class RowValue(StrAndUnicode):\r
+ """Very basic wrapper around a single row value of a column.\r
+\r
+ Instead of returning the row values directly, ``BoundRow`` spawns\r
+ instances of this class. That's necessary since the ``choices``\r
+ feature means that a single row value can consist of both the value\r
+ itself and an associated ID.\r
+ """\r
+ def __init__(self, value, column):\r
+ if column.column.choices == True:\r
+ if isinstance(value, dict):\r
+ self.id = value.get('id')\r
+ self.value = value.get('value')\r
+ elif isinstance(value, (tuple,list,)):\r
+ self.id = value[0]\r
+ self.value = value[1]\r
+ else:\r
+ self.id = None\r
+ self.value = value\r
+ else:\r
+ self.id = None\r
+ self.value = value\r
+\r
+ def __unicode__(self):\r
+ return unicode(self.value)
\ No newline at end of file
assert not 'id' in r\r
# missing data is available as default\r
assert 'answer' in r\r
- assert r['answer'] == 42 # note: different from prev. line!\r
+ assert r['answer'].value == 42 # note: different from prev. line!\r
\r
# all that still works when name overrides are used\r
assert not 'c' in r\r
assert 'count' in r\r
- assert r['count'] == 1\r
+ assert r['count'].value == 1\r
\r
# changing an instance's base_columns does not change the class\r
assert id(books.base_columns) != id(BookTable.base_columns)\r
books.base_columns['language'].sortable = False\r
books.order_by = 'language'\r
assert not books.order_by\r
- test_order(('language', 'num_pages'), [1,3,2,4]) # as if: 'num_pages'
\ No newline at end of file
+ test_order(('language', 'num_pages'), [1,3,2,4]) # as if: 'num_pages'\r
+\r
+def test_choices():\r
+ # unrestricted choices\r
+ class BookTable(tables.Table):\r
+ id = tables.Column()\r
+ name = tables.Column()\r
+ author = tables.Column(choices=True)\r
+\r
+ books = BookTable([\r
+ {'id': 1, 'name': 'A'},\r
+ {'id': 2, 'author': (99, 'Mr. Vanderlay'), 'name': 'B'},\r
+ {'id': 3, 'author': 'Mr. Vanderlay', 'name': 'C'},\r
+ {'id': 4, 'author': {'id': 99, 'value': 'Mr. Vanderlay'}, 'name': 'D'},\r
+ ])\r
+\r
+ assert [r['author'].id for r in books.rows] == [None, 99, None, 99]\r
+ assert [r['author'].value for r in books.rows] == [None, 'Mr. Vanderlay', 'Mr. Vanderlay', 'Mr. Vanderlay']\r
+\r
+ # TODO: restricted choices (planned)
\ No newline at end of file
countries.order_by = ('custom1', 'custom2')\r
assert countries.order_by == ()\r
\r
+def test_choices():\r
+ pass # TODO\r
+\r
def test_pagination():\r
pass\r
\r
-# TODO: foreignkey columns: simply support foreignkeys, tuples and id, name dicts; support column choices attribute to validate id-only\r
# TODO: pagination\r
# TODO: support function column sources both for modeltables (methods on model) and static tables (functions in dict)\r
# TODO: manual base columns change -> update() call (add as example in docstr here) -> rebuild snapshot: is row cache, column cache etc. reset?\r
-# TODO: throw an exception on invalid order_by
\ No newline at end of file
+# TODO: throw an exception on invalid order_by\r
+# TODO: option to skip model table generation (leave off model option?)
\ No newline at end of file