added minor test
[django-tables2.git] / tests / test_models.py
1 """Test ModelTable specific functionality.\r
2 \r
3 Sets up a temporary Django project using a memory SQLite database.\r
4 """\r
5 \r
6 from django.conf import settings\r
7 import django_tables as tables\r
8 \r
9 def setup_module(module):\r
10     settings.configure(**{\r
11         'DATABASE_ENGINE': 'sqlite3',\r
12         'DATABASE_NAME': ':memory:',\r
13         'INSTALLED_APPS': ('tests.testapp',)\r
14     })\r
15 \r
16     from django.db import models\r
17     from django.core.management import call_command\r
18 \r
19     class City(models.Model):\r
20         name = models.TextField()\r
21         population = models.IntegerField()\r
22         class Meta:\r
23             app_label = 'testapp'\r
24     module.City = City\r
25 \r
26     class Country(models.Model):\r
27         name = models.TextField()\r
28         population = models.IntegerField()\r
29         capital = models.ForeignKey(City, blank=True, null=True)\r
30         tld = models.TextField(verbose_name='Domain Extension', max_length=2)\r
31         system = models.TextField(blank=True, null=True)\r
32         null = models.TextField(blank=True, null=True)  # tests expect this to be always null!\r
33         class Meta:\r
34             app_label = 'testapp'\r
35     module.Country = Country\r
36 \r
37     # create the tables\r
38     call_command('syncdb', verbosity=1, interactive=False)\r
39 \r
40     # create a couple of objects\r
41     Country(name="Austria", tld="au", population=8, system="republic").save()\r
42     Country(name="Germany", tld="de", population=81).save()\r
43     Country(name="France", tld="fr", population=64, system="republic").save()\r
44     Country(name="Netherlands", tld="nl", population=16, system="monarchy").save()\r
45 \r
46 def test_declaration():\r
47     """Test declaration, declared columns and default model field columns.\r
48     """\r
49 \r
50     class CountryTable(tables.ModelTable):\r
51         class Meta:\r
52             model = Country\r
53 \r
54     assert len(CountryTable.base_columns) == 7\r
55     assert 'name' in CountryTable.base_columns\r
56     assert not hasattr(CountryTable, 'name')\r
57 \r
58     # Override one model column, add another custom one, exclude one\r
59     class CountryTable(tables.ModelTable):\r
60         capital = tables.TextColumn(verbose_name='Name of capital')\r
61         projected = tables.Column(verbose_name="Projected Population")\r
62         class Meta:\r
63             model = Country\r
64             exclude = ['tld']\r
65 \r
66     assert len(CountryTable.base_columns) == 7\r
67     assert 'projected' in CountryTable.base_columns\r
68     assert 'capital' in CountryTable.base_columns\r
69     assert not 'tld' in CountryTable.base_columns\r
70 \r
71     # Inheritance (with a different model) + field restrictions\r
72     class CityTable(CountryTable):\r
73         class Meta:\r
74             model = City\r
75             columns = ['id', 'name']\r
76             exclude = ['capital']\r
77 \r
78     print CityTable.base_columns\r
79     assert len(CityTable.base_columns) == 4\r
80     assert 'id' in CityTable.base_columns\r
81     assert 'name' in CityTable.base_columns\r
82     assert 'projected' in CityTable.base_columns # declared in parent\r
83     assert not 'population' in CityTable.base_columns  # not in Meta:columns\r
84     assert 'capital' in CityTable.base_columns  # in exclude, but only works on model fields (is that the right behaviour?)\r
85 \r
86 def test_basic():\r
87     """Some tests here are copied from ``test_basic.py`` but need to be\r
88     rerun with a ModelTable, as the implementation is different."""\r
89     class CountryTable(tables.ModelTable):\r
90         null = tables.Column(default="foo")\r
91         tld = tables.Column(name="domain")\r
92         class Meta:\r
93             model = Country\r
94             exclude = ('id',)\r
95     countries = CountryTable()\r
96 \r
97     for r in countries.rows:\r
98         # "normal" fields exist\r
99         assert 'name' in r\r
100         # unknown fields are removed/not accessible\r
101         assert not 'does-not-exist' in r\r
102         # ...so are excluded fields\r
103         assert not 'id' in r\r
104         # missing data is available with default values\r
105         assert 'null' in r\r
106         assert r['null'] == "foo"   # note: different from prev. line!\r
107 \r
108         # all that still works when name overrides are used\r
109         assert not 'tld' in r\r
110         assert 'domain' in r\r
111         assert len(r['domain']) == 2   # valid country tld\r
112 \r
113     # make sure the row and column caches work for model tables as well\r
114     assert id(list(countries.columns)[0]) == id(list(countries.columns)[0])\r
115     # TODO: row cache currently not used\r
116     #assert id(list(countries.rows)[0]) == id(list(countries.rows)[0])\r
117 \r
118 def test_sort():\r
119     class CountryTable(tables.ModelTable):\r
120         tld = tables.Column(name="domain")\r
121         system = tables.Column(default="republic")\r
122         custom1 = tables.Column()\r
123         custom2 = tables.Column(sortable=True)\r
124         class Meta:\r
125             model = Country\r
126     countries = CountryTable()\r
127 \r
128     def test_order(order, result):\r
129         countries.order_by = order\r
130         assert [r['id'] for r in countries.rows] == result\r
131 \r
132     # test various orderings\r
133     test_order(('population',), [1,4,3,2])\r
134     test_order(('-population',), [2,3,4,1])\r
135     test_order(('name',), [1,3,2,4])\r
136     # test sorting by a "rewritten" column name\r
137     countries.order_by = 'domain,tld'\r
138     countries.order_by == ('domain',)\r
139     test_order(('-domain',), [4,3,2,1])\r
140     # test multiple order instructions; note: one row is missing a "system"\r
141     # value, but has a default set; however, that has no effect on sorting.\r
142     test_order(('system', '-population'), [2,4,3,1])\r
143     # using a simple string (for convinience as well as querystring passing\r
144     test_order('-population', [2,3,4,1])\r
145     test_order('system,-population', [2,4,3,1])\r
146 \r
147     # test invalid order instructions...\r
148     countries.order_by = 'invalid_field,population'\r
149     assert countries.order_by == ('population',)\r
150     # ...in case of ModelTables, this primarily means that only\r
151     # model-based colunns are currently sortable at all.\r
152     countries.order_by = ('custom1', 'custom2')\r
153     assert countries.order_by == ()\r
154 \r
155 def test_pagination():\r
156     pass\r
157 \r
158 # TODO: foreignkey columns: simply support foreignkeys, tuples and id, name dicts; support column choices attribute to validate id-only\r
159 # TODO: pagination\r
160 # TODO: support function column sources both for modeltables (methods on model) and static tables (functions in dict)\r
161 # TODO: manual base columns change -> update() call (add as example in docstr here) -> rebuild snapshot: is row cache, column cache etc. reset?\r
162 # TODO: throw an exception on invalid order_by