added default 'order_by' option to tables.
authoradammck <adam.mckaig@gmail.com>
Fri, 16 Apr 2010 03:17:22 +0000 (23:17 -0400)
committerMichael Elsdoerfer <michael@elsdoerfer.com>
Wed, 21 Apr 2010 06:58:52 +0000 (08:58 +0200)
this allows tables to specify a default sort order, which includes all
of the UI of an explicitly-sorted dataset.

also, some tests. they fail for BaseTable, because sorting doesn't seem
to be implemented there. it should be, though, despite being crazy.

django_tables/base.py
tests/test_basic.py
tests/test_models.py

index d0052269c4e76e1e6d5d13c642760dc001c4c3da..b08e061d4e3eab69464a682f5eb7fb764c74e6ea 100644 (file)
@@ -15,6 +15,7 @@ class TableOptions(object):
     def __init__(self, options=None):\r
         super(TableOptions, self).__init__()\r
         self.sortable = getattr(options, 'sortable', None)\r
+        self.order_by = getattr(options, 'order_by', None)\r
 \r
 \r
 class DeclarativeColumnsMetaclass(type):\r
@@ -419,10 +420,16 @@ class BaseTable(object):
 \r
     rows_class = Rows\r
 \r
-    def __init__(self, data, order_by=None):\r
+    # this value is not the same as None. it means 'use the default sort\r
+    # order', which may (or may not) be inherited from the table options.\r
+    # None means 'do not sort the data', ignoring the default.\r
+    DefaultOrder = type('DefaultSortType', (), {})()\r
+\r
+    def __init__(self, data, order_by=DefaultOrder):\r
         """Create a new table instance with the iterable ``data``.\r
 \r
         If ``order_by`` is specified, the data will be sorted accordingly.\r
+        Otherwise, the sort order can be specified in the table options.\r
 \r
         Note that unlike a ``Form``, tables are always bound to data. Also\r
         unlike a form, the ``columns`` attribute is read-only and returns\r
@@ -439,7 +446,14 @@ class BaseTable(object):
         self._rows = self.rows_class(self)\r
         self._columns = Columns(self)\r
 \r
-        self.order_by = order_by\r
+        # None is a valid order, so we must use DefaultOrder as a flag\r
+        # to fall back to the table sort order. set the attr via the\r
+        # property, to wrap it in an OrderByTuple before being stored\r
+        if order_by != BaseTable.DefaultOrder:\r
+            self.order_by = order_by\r
+\r
+        else:\r
+            self.order_by = self._meta.order_by\r
 \r
         # Make a copy so that modifying this will not touch the class\r
         # definition. Note that this is different from forms, where the\r
@@ -545,6 +559,7 @@ class BaseTable(object):
             self._order_by = OrderByTuple(validated_order_by)\r
         else:\r
             self._order_by = OrderByTuple()\r
+\r
     order_by = property(lambda s: s._order_by, _set_order_by)\r
 \r
     def __unicode__(self):\r
index fe942789175b62145c7c0ebdca2c4e7cbfbabf19..4271a7d5b348133afad9cd8694e0e2b439bc7b12 100644 (file)
@@ -2,7 +2,7 @@
 """
 
 
-from nose.tools import assert_raises
+from nose.tools import assert_raises, assert_equal
 from django.http import Http404
 from django.core.paginator import Paginator
 import django_tables as tables
@@ -53,6 +53,64 @@ def test_declaration():
     assert 'motto' in StateTable2.base_columns
 
 
+def test_sort():
+    class MyUnsortedTable(TestTable):
+        alpha  = tables.Column()
+        beta   = tables.Column()
+        n      = tables.Column()
+
+    test_data = [
+        {'alpha': "mmm", 'beta': "mmm", 'n': 1 },
+        {'alpha': "aaa", 'beta': "zzz", 'n': 2 },
+        {'alpha': "zzz", 'beta': "aaa", 'n': 3 }]
+
+    # unsorted (default) preserves order
+    assert_equal(1, MyUnsortedTable(test_data               ).rows[0]['n'])
+    assert_equal(1, MyUnsortedTable(test_data, order_by=None).rows[0]['n'])
+    assert_equal(1, MyUnsortedTable(test_data, order_by=[]  ).rows[0]['n'])
+    assert_equal(1, MyUnsortedTable(test_data, order_by=()  ).rows[0]['n'])
+
+    # values of order_by are wrapped in tuples before being returned
+    assert_equal(('alpha',), MyUnsortedTable([], order_by='alpha').order_by)
+    assert_equal(('beta',),  MyUnsortedTable([], order_by=('beta',)).order_by)
+    assert_equal((),         MyUnsortedTable([]).order_by)
+
+    # a rewritten order_by is also wrapped
+    table = MyUnsortedTable([])
+    table.order_by = 'alpha'
+    assert_equal(('alpha',), table.order_by)
+
+    # data can be sorted by any column
+    assert_equal(2, MyUnsortedTable(test_data, order_by='alpha').rows[0]['n'])
+    assert_equal(3, MyUnsortedTable(test_data, order_by='beta' ).rows[0]['n'])
+
+    # default sort order can be specified in table options
+    class MySortedTable(MyUnsortedTable):
+        class Meta:
+            order_by = 'alpha'
+
+    # order_by is inherited from the options if not explitly set
+    table = MySortedTable(test_data)
+    assert_equal(('alpha',), table.order_by)
+    assert_equal(2, table.rows[0]['n'])
+
+    # ...but can be overloaded at __init___
+    table = MySortedTable(test_data, order_by='beta')
+    assert_equal(('beta',), table.order_by)
+    assert_equal(3, table.rows[0]['n'])
+
+    # ...or rewritten later
+    table = MySortedTable(test_data)
+    table.order_by = 'beta'
+    assert_equal(('beta',), table.order_by)
+    assert_equal(3, table.rows[0]['n'])
+
+    # ...or reset to None (unsorted), ignoring the table default
+    table = MySortedTable(test_data, order_by=None)
+    assert_equal((), table.order_by)
+    assert_equal(1, table.rows[0]['n'])
+
+
 def test_column_count():
     class MyTable(TestTable):
         visbible = tables.Column(visible=True)
index 61f97b03d69c7ece376b53e4b84ad34775e14f39..47485a0c30a9e7b8746e31c3cc8cd753fbaccf2d 100644 (file)
@@ -3,7 +3,7 @@
 Sets up a temporary Django project using a memory SQLite database.\r
 """\r
 \r
-from nose.tools import assert_raises\r
+from nose.tools import assert_raises, assert_equal\r
 from django.conf import settings\r
 from django.core.paginator import *\r
 import django_tables as tables\r
@@ -206,6 +206,20 @@ def test_sort():
     countries.order_by = ('custom1', 'custom2')\r
     assert countries.order_by == ()\r
 \r
+def test_default_sort():\r
+    class SortedCountryTable(tables.ModelTable):\r
+        class Meta:\r
+            model = Country\r
+            order_by = '-name'\r
+\r
+    # the default order can be inherited from the table\r
+    assert_equal(('-name',), SortedCountryTable().order_by)\r
+    assert_equal(4, SortedCountryTable().rows[0]['id'])\r
+\r
+    # and explicitly set (or reset) via __init__\r
+    assert_equal(2, SortedCountryTable(order_by='system').rows[0]['id'])\r
+    assert_equal(1, SortedCountryTable(order_by=None).rows[0]['id'])\r
+\r
 def test_callable():\r
     """Some of the callable code is reimplemented for modeltables, so\r
     test some specifics again.\r