1 """Test ModelTable specific functionality.
\r
3 Sets up a temporary Django project using a memory SQLite database.
\r
6 from django.conf import settings
\r
7 import django_tables as tables
\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
16 from django.db import models
\r
17 from django.core.management import call_command
\r
19 class City(models.Model):
\r
20 name = models.TextField()
\r
21 population = models.IntegerField()
\r
23 app_label = 'testapp'
\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
34 app_label = 'testapp'
\r
35 module.Country = Country
\r
38 call_command('syncdb', verbosity=1, interactive=False)
\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
46 def test_declaration():
\r
47 """Test declaration, declared columns and default model field columns.
\r
50 class CountryTable(tables.ModelTable):
\r
54 assert len(CountryTable.base_columns) == 7
\r
55 assert 'name' in CountryTable.base_columns
\r
56 assert not hasattr(CountryTable, 'name')
\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
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
71 # Inheritance (with a different model) + field restrictions
\r
72 class CityTable(CountryTable):
\r
75 columns = ['id', 'name']
\r
76 exclude = ['capital']
\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
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
95 countries = CountryTable()
\r
97 for r in countries.rows:
\r
98 # "normal" fields exist
\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
106 assert r['null'] == "foo" # note: different from prev. line!
\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
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
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
126 countries = CountryTable()
\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
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
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
155 def test_pagination():
\r
158 # TODO: foreignkey columns: simply support foreignkeys, tuples and id, name dicts; support column choices attribute to validate id-only
\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