standard tables now support an inner metaclass; the new 'sortable' option allows...
authorMichael Elsdoerfer <michael@elsdoerfer.info>
Sun, 29 Jun 2008 13:13:30 +0000 (15:13 +0200)
committerMichael Elsdoerfer <michael@elsdoerfer.info>
Sun, 29 Jun 2008 13:13:30 +0000 (15:13 +0200)
README
django_tables/columns.py
django_tables/models.py
django_tables/tables.py
tests/test_basic.py

diff --git a/README b/README
index 4467b37dff245dbe4d889ab41066f2e9733744bd..71ae0965df509240e040a991c34329b190a3d1c3 100644 (file)
--- a/README
+++ b/README
@@ -122,6 +122,21 @@ the row instance as an argument (representing the row that the default is
 needed for).\r
 \r
 \r
+Table Options\r
+-------------\r
+\r
+Table-specific options are implemented using the same inner ``Meta`` class\r
+concept as known from forms and models in Django:\r
+\r
+    class MyTable(tables.Table):\r
+        class Meta:\r
+            sortable = True\r
+\r
+Currently, for non-model tables, the only supported option is ``sortable``.\r
+Per default, all columns are sortable, unless a column specifies otherwise.\r
+This meta option allows you to overwrite the global default for the table.\r
+\r
+\r
 ModelTables\r
 -----------\r
 \r
index 51e71b1f38708ed4107d7e23b35df51bc7d61a9d..b715f1462d9c08c9869d960abc03538e9adeb273 100644 (file)
@@ -41,7 +41,7 @@ class Column(object):
     creation_counter = 0\r
 \r
     def __init__(self, verbose_name=None, name=None, default=None, data=None,\r
-                 visible=True, inaccessible=False, sortable=True):\r
+                 visible=True, inaccessible=False, sortable=None):\r
         self.verbose_name = verbose_name\r
         self.name = name\r
         self.default = default\r
index 9aea7353e7614f5a6c395e774ed3ca1e878de4ec..3f4e7945d0d4a65ea90b87f3ca940b7d25806efb 100644 (file)
@@ -1,12 +1,13 @@
 from django.core.exceptions import FieldError\r
 from django.utils.datastructures import SortedDict\r
 from tables import BaseTable, DeclarativeColumnsMetaclass, \\r
-    Column, BoundRow, Rows\r
+    Column, BoundRow, Rows, TableOptions\r
 \r
 __all__ = ('BaseModelTable', 'ModelTable')\r
 \r
-class ModelTableOptions(object):\r
+class ModelTableOptions(TableOptions):\r
     def __init__(self, options=None):\r
+        super(ModelTableOptions, self).__init__()\r
         self.model = getattr(options, 'model', None)\r
         self.columns = getattr(options, 'columns', None)\r
         self.exclude = getattr(options, 'exclude', None)\r
index 7a284a0a2be66b6f136c95942fb98a775af0dbb8..56a9e3351a5db3f5282b578843cc7b80c0d3ac54 100644 (file)
@@ -28,6 +28,11 @@ def sort_table(data, order_by):
             instructions.append((o, False,))\r
     data.sort(cmp=_cmp)\r
 \r
+class TableOptions(object):\r
+    def __init__(self, options=None):\r
+        super(TableOptions, self).__init__()\r
+        self.sortable = getattr(options, 'sortable', None)\r
+\r
 class DeclarativeColumnsMetaclass(type):\r
     """\r
     Metaclass that converts Column attributes to a dictionary called\r
@@ -83,6 +88,7 @@ class DeclarativeColumnsMetaclass(type):
             attrs['base_columns'] = SortedDict()\r
         attrs['base_columns'].update(SortedDict(columns))\r
 \r
+        attrs['_meta'] = TableOptions(attrs.get('Meta', None))\r
         return type.__new__(cls, name, bases, attrs)\r
 \r
 def rmprefix(s):\r
@@ -298,7 +304,7 @@ class BaseTable(object):
         """\r
         if purpose == 'order_by':\r
             return name in self.columns and\\r
-                   self.columns[name].column.sortable\r
+                   self.columns[name].sortable\r
         else:\r
             return True\r
 \r
@@ -471,9 +477,17 @@ class BoundColumn(StrAndUnicode):
         self.column = column\r
         self.declared_name = name\r
         # expose some attributes of the column more directly\r
-        self.sortable = column.sortable\r
         self.visible = column.visible\r
 \r
+    def _get_sortable(self):\r
+        if self.column.sortable is not None:\r
+            return self.column.sortable\r
+        elif self.table._meta.sortable is not None:\r
+            return self.table._meta.sortable\r
+        else:\r
+            return True   # the default value\r
+    sortable = property(_get_sortable)\r
+\r
     name = property(lambda s: s.column.name or s.declared_name)\r
     name_reversed = property(lambda s: "-"+s.name)\r
     def _get_name_toggled(self):\r
index 589bbfced1aedb85e7335ba5115345f6a87ed026..48c67a33b018fe25059732951bf70ea5770e206b 100644 (file)
@@ -126,6 +126,32 @@ def test_caches():
     assert id(list(books.columns)[0]) != old_column_cache\r
     assert id(list(books.rows)[0]) != old_row_cache\r
 \r
+def test_meta_sortable():\r
+    """Specific tests for sortable table meta option."""\r
+\r
+    def mktable(default_sortable):\r
+        class BookTable(tables.Table):\r
+            id = tables.Column(sortable=True)\r
+            name = tables.Column(sortable=False)\r
+            author = tables.Column()\r
+            class Meta:\r
+                sortable = default_sortable\r
+        return BookTable([])\r
+\r
+    global_table = mktable(None)\r
+    for default_sortable, results in (\r
+        (None,      (True, False, True)),    # last bool is global default\r
+        (True,      (True, False, True)),    # last bool is table default\r
+        (False,     (True, False, False)),   # last bool is table default\r
+    ):\r
+        books = mktable(default_sortable)\r
+        assert [c.sortable for c in books.columns] == list(results)\r
+\r
+        # it also works if the meta option is manually changed after\r
+        # class and instance creation\r
+        global_table._meta.sortable = default_sortable\r
+        assert [c.sortable for c in global_table.columns] == list(results)\r
+\r
 def test_sort():\r
     class BookTable(tables.Table):\r
         id = tables.Column()\r