added default 'order_by' option to tables.
[django-tables2.git] / tests / test_basic.py
1 """Test the core table functionality.
2 """
3
4
5 from nose.tools import assert_raises, assert_equal
6 from django.http import Http404
7 from django.core.paginator import Paginator
8 import django_tables as tables
9 from django_tables.base import BaseTable
10
11
12 class TestTable(BaseTable):
13     pass
14
15
16 def test_declaration():
17     """
18     Test defining tables by declaration.
19     """
20
21     class GeoAreaTable(TestTable):
22         name = tables.Column()
23         population = tables.Column()
24
25     assert len(GeoAreaTable.base_columns) == 2
26     assert 'name' in GeoAreaTable.base_columns
27     assert not hasattr(GeoAreaTable, 'name')
28
29     class CountryTable(GeoAreaTable):
30         capital = tables.Column()
31
32     assert len(CountryTable.base_columns) == 3
33     assert 'capital' in CountryTable.base_columns
34
35     # multiple inheritance
36     class AddedMixin(TestTable):
37         added = tables.Column()
38     class CityTable(GeoAreaTable, AddedMixin):
39         mayer = tables.Column()
40
41     assert len(CityTable.base_columns) == 4
42     assert 'added' in CityTable.base_columns
43
44     # modelforms: support switching from a non-model table hierarchy to a
45     # modeltable hierarchy (both base class orders)
46     class StateTable1(tables.ModelTable, GeoAreaTable):
47         motto = tables.Column()
48     class StateTable2(GeoAreaTable, tables.ModelTable):
49         motto = tables.Column()
50
51     assert len(StateTable1.base_columns) == len(StateTable2.base_columns) == 3
52     assert 'motto' in StateTable1.base_columns
53     assert 'motto' in StateTable2.base_columns
54
55
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
114 def test_column_count():
115     class MyTable(TestTable):
116         visbible = tables.Column(visible=True)
117         hidden = tables.Column(visible=False)
118
119     # The columns container supports the len() builtin
120     assert len(MyTable([]).columns) == 1
121
122
123 def test_pagination():
124     class BookTable(TestTable):
125         name = tables.Column()
126
127     # create some sample data
128     data = []
129     for i in range(1,101):
130         data.append({'name': 'Book Nr. %d'%i})
131     books = BookTable(data)
132
133     # external paginator
134     paginator = Paginator(books.rows, 10)
135     assert paginator.num_pages == 10
136     page = paginator.page(1)
137     assert len(page.object_list) == 10
138     assert page.has_previous() == False
139     assert page.has_next() == True
140
141     # integrated paginator
142     books.paginate(Paginator, 10, page=1)
143     # rows is now paginated
144     assert len(list(books.rows.page())) == 10
145     assert len(list(books.rows.all())) == 100
146     # new attributes
147     assert books.paginator.num_pages == 10
148     assert books.page.has_previous() == False
149     assert books.page.has_next() == True
150     # exceptions are converted into 404s
151     assert_raises(Http404, books.paginate, Paginator, 10, page=9999)
152     assert_raises(Http404, books.paginate, Paginator, 10, page="abc")