Skip to content

Commit 5047081

Browse files
adammckmiracle2k
authored andcommitted
added default 'order_by' option to tables.
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.
1 parent 5ee0080 commit 5047081

File tree

3 files changed

+91
-4
lines changed

3 files changed

+91
-4
lines changed

django_tables/base.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TableOptions(object):
1515
def __init__(self, options=None):
1616
super(TableOptions, self).__init__()
1717
self.sortable = getattr(options, 'sortable', None)
18+
self.order_by = getattr(options, 'order_by', None)
1819

1920

2021
class DeclarativeColumnsMetaclass(type):
@@ -419,10 +420,16 @@ class BaseTable(object):
419420

420421
rows_class = Rows
421422

422-
def __init__(self, data, order_by=None):
423+
# this value is not the same as None. it means 'use the default sort
424+
# order', which may (or may not) be inherited from the table options.
425+
# None means 'do not sort the data', ignoring the default.
426+
DefaultOrder = type('DefaultSortType', (), {})()
427+
428+
def __init__(self, data, order_by=DefaultOrder):
423429
"""Create a new table instance with the iterable ``data``.
424430
425431
If ``order_by`` is specified, the data will be sorted accordingly.
432+
Otherwise, the sort order can be specified in the table options.
426433
427434
Note that unlike a ``Form``, tables are always bound to data. Also
428435
unlike a form, the ``columns`` attribute is read-only and returns
@@ -439,7 +446,14 @@ def __init__(self, data, order_by=None):
439446
self._rows = self.rows_class(self)
440447
self._columns = Columns(self)
441448

442-
self.order_by = order_by
449+
# None is a valid order, so we must use DefaultOrder as a flag
450+
# to fall back to the table sort order. set the attr via the
451+
# property, to wrap it in an OrderByTuple before being stored
452+
if order_by != BaseTable.DefaultOrder:
453+
self.order_by = order_by
454+
455+
else:
456+
self.order_by = self._meta.order_by
443457

444458
# Make a copy so that modifying this will not touch the class
445459
# definition. Note that this is different from forms, where the
@@ -545,6 +559,7 @@ def _set_order_by(self, value):
545559
self._order_by = OrderByTuple(validated_order_by)
546560
else:
547561
self._order_by = OrderByTuple()
562+
548563
order_by = property(lambda s: s._order_by, _set_order_by)
549564

550565
def __unicode__(self):

tests/test_basic.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33

44

5-
from nose.tools import assert_raises
5+
from nose.tools import assert_raises, assert_equal
66
from django.http import Http404
77
from django.core.paginator import Paginator
88
import django_tables as tables
@@ -53,6 +53,64 @@ class StateTable2(GeoAreaTable, tables.ModelTable):
5353
assert 'motto' in StateTable2.base_columns
5454

5555

56+
def test_sort():
57+
class MyUnsortedTable(TestTable):
58+
alpha = tables.Column()
59+
beta = tables.Column()
60+
n = tables.Column()
61+
62+
test_data = [
63+
{'alpha': "mmm", 'beta': "mmm", 'n': 1 },
64+
{'alpha': "aaa", 'beta': "zzz", 'n': 2 },
65+
{'alpha': "zzz", 'beta': "aaa", 'n': 3 }]
66+
67+
# unsorted (default) preserves order
68+
assert_equal(1, MyUnsortedTable(test_data ).rows[0]['n'])
69+
assert_equal(1, MyUnsortedTable(test_data, order_by=None).rows[0]['n'])
70+
assert_equal(1, MyUnsortedTable(test_data, order_by=[] ).rows[0]['n'])
71+
assert_equal(1, MyUnsortedTable(test_data, order_by=() ).rows[0]['n'])
72+
73+
# values of order_by are wrapped in tuples before being returned
74+
assert_equal(('alpha',), MyUnsortedTable([], order_by='alpha').order_by)
75+
assert_equal(('beta',), MyUnsortedTable([], order_by=('beta',)).order_by)
76+
assert_equal((), MyUnsortedTable([]).order_by)
77+
78+
# a rewritten order_by is also wrapped
79+
table = MyUnsortedTable([])
80+
table.order_by = 'alpha'
81+
assert_equal(('alpha',), table.order_by)
82+
83+
# data can be sorted by any column
84+
assert_equal(2, MyUnsortedTable(test_data, order_by='alpha').rows[0]['n'])
85+
assert_equal(3, MyUnsortedTable(test_data, order_by='beta' ).rows[0]['n'])
86+
87+
# default sort order can be specified in table options
88+
class MySortedTable(MyUnsortedTable):
89+
class Meta:
90+
order_by = 'alpha'
91+
92+
# order_by is inherited from the options if not explitly set
93+
table = MySortedTable(test_data)
94+
assert_equal(('alpha',), table.order_by)
95+
assert_equal(2, table.rows[0]['n'])
96+
97+
# ...but can be overloaded at __init___
98+
table = MySortedTable(test_data, order_by='beta')
99+
assert_equal(('beta',), table.order_by)
100+
assert_equal(3, table.rows[0]['n'])
101+
102+
# ...or rewritten later
103+
table = MySortedTable(test_data)
104+
table.order_by = 'beta'
105+
assert_equal(('beta',), table.order_by)
106+
assert_equal(3, table.rows[0]['n'])
107+
108+
# ...or reset to None (unsorted), ignoring the table default
109+
table = MySortedTable(test_data, order_by=None)
110+
assert_equal((), table.order_by)
111+
assert_equal(1, table.rows[0]['n'])
112+
113+
56114
def test_column_count():
57115
class MyTable(TestTable):
58116
visbible = tables.Column(visible=True)

tests/test_models.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Sets up a temporary Django project using a memory SQLite database.
44
"""
55

6-
from nose.tools import assert_raises
6+
from nose.tools import assert_raises, assert_equal
77
from django.conf import settings
88
from django.core.paginator import *
99
import django_tables as tables
@@ -206,6 +206,20 @@ class Meta:
206206
countries.order_by = ('custom1', 'custom2')
207207
assert countries.order_by == ()
208208

209+
def test_default_sort():
210+
class SortedCountryTable(tables.ModelTable):
211+
class Meta:
212+
model = Country
213+
order_by = '-name'
214+
215+
# the default order can be inherited from the table
216+
assert_equal(('-name',), SortedCountryTable().order_by)
217+
assert_equal(4, SortedCountryTable().rows[0]['id'])
218+
219+
# and explicitly set (or reset) via __init__
220+
assert_equal(2, SortedCountryTable(order_by='system').rows[0]['id'])
221+
assert_equal(1, SortedCountryTable(order_by=None).rows[0]['id'])
222+
209223
def test_callable():
210224
"""Some of the callable code is reimplemented for modeltables, so
211225
test some specifics again.

0 commit comments

Comments
 (0)