renamed to django-tables2
[django-tables2.git] / tests / models.py
1 import itertools
2 from django.conf import settings
3 from django.test.client import RequestFactory
4 from django.template import Template, Context
5 import django_tables2 as tables
6 from django_attest import TransactionTestContext
7 from attest import Tests, Assert
8 from .testapp.models import Person, Occupation
9
10
11 models = Tests()
12 models.context(TransactionTestContext())
13
14
15 class PersonTable(tables.Table):
16     first_name = tables.Column()
17     last_name = tables.Column()
18     occupation = tables.Column()
19
20
21 @models.test
22 def boundrows_iteration():
23     occupation = Occupation.objects.create(name='Programmer')
24     Person.objects.create(first_name='Bradley', last_name='Ayers', occupation=occupation)
25     Person.objects.create(first_name='Chris',   last_name='Doble', occupation=occupation)
26
27     table = PersonTable(Person.objects.all())
28     records = [row.record for row in table.rows]
29     expecteds = Person.objects.all()
30     for expected, actual in itertools.izip(expecteds, records):
31         Assert(expected) == actual
32
33
34 @models.test
35 def model_table():
36     """
37     The ``model`` option on a table causes the table to dynamically add columns
38     based on the fields.
39     """
40     class OccupationTable(tables.Table):
41         class Meta:
42             model = Occupation
43     Assert(["id", "name", "region"]) == OccupationTable.base_columns.keys()
44
45     class OccupationTable2(tables.Table):
46         extra = tables.Column()
47         class Meta:
48             model = Occupation
49     Assert(["id", "name", "region", "extra"]) == OccupationTable2.base_columns.keys()
50
51     # be aware here, we already have *models* variable, but we're importing
52     # over the top
53     from django.db import models
54     class ComplexModel(models.Model):
55         char = models.CharField(max_length=200)
56         fk = models.ForeignKey("self")
57         m2m = models.ManyToManyField("self")
58
59     class ComplexTable(tables.Table):
60         class Meta:
61             model = ComplexModel
62     Assert(["id", "char", "fk"]) == ComplexTable.base_columns.keys()
63
64
65 @models.test
66 def mixins():
67     class TableMixin(tables.Table):
68         extra = tables.Column()
69
70     class OccupationTable(TableMixin, tables.Table):
71         extra2 = tables.Column()
72         class Meta:
73             model = Occupation
74     Assert(["extra", "id", "name", "region", "extra2"]) == OccupationTable.base_columns.keys()
75
76
77 @models.test
78 def verbose_name():
79     """
80     When using queryset data as input for a table, default to using model field
81     verbose names rather than an autogenerated string based on the column name.
82
83     However if a column does explicitly describe a verbose name, it should be
84     used.
85     """
86     class PersonTable(tables.Table):
87         """
88         The test_colX columns are to test that the accessor is used to
89         determine the field on the model, rather than the column name.
90         """
91         first_name = tables.Column()
92         fn1 = tables.Column(accessor='first_name')
93         fn2 = tables.Column(accessor='first_name.upper')
94         fn3 = tables.Column(accessor='last_name', verbose_name='OVERRIDE')
95         last_name = tables.Column()
96         ln1 = tables.Column(accessor='last_name')
97         ln2 = tables.Column(accessor='last_name.upper')
98         ln3 = tables.Column(accessor='last_name', verbose_name='OVERRIDE')
99         region = tables.Column(accessor='occupation.region.name')
100         r1 = tables.Column(accessor='occupation.region.name')
101         r2 = tables.Column(accessor='occupation.region.name.upper')
102         r3 = tables.Column(accessor='occupation.region.name', verbose_name='OVERRIDE')
103
104     # The Person model has a ``first_name`` and ``last_name`` field, but only
105     # the ``last_name`` field has an explicit ``verbose_name`` set. This means
106     # that we should expect that the two columns that use the ``last_name``
107     # field should both use the model's ``last_name`` field's ``verbose_name``,
108     # however both fields that use the ``first_name`` field should just use a
109     # capitalized version of the column name as the column header.
110     table = PersonTable(Person.objects.all())
111     # Should be generated (capitalized column name)
112     Assert('First name') == table.columns['first_name'].verbose_name
113     Assert('First name') == table.columns['fn1'].verbose_name
114     Assert('First name') == table.columns['fn2'].verbose_name
115     Assert('OVERRIDE') == table.columns['fn3'].verbose_name
116     # Should use the model field's verbose_name
117     Assert('Surname') == table.columns['last_name'].verbose_name
118     Assert('Surname') == table.columns['ln1'].verbose_name
119     Assert('Surname') == table.columns['ln2'].verbose_name
120     Assert('OVERRIDE') == table.columns['ln3'].verbose_name
121     Assert('Name') == table.columns['region'].verbose_name
122     Assert('Name') == table.columns['r1'].verbose_name
123     Assert('Name') == table.columns['r2'].verbose_name
124     Assert('OVERRIDE') == table.columns['r3'].verbose_name
125
126 @models.test
127 def column_mapped_to_nonexistant_field():
128     """
129     Issue #9 describes how if a Table has a column that has an accessor that
130     targets a non-existent field, a FieldDoesNotExist error is raised.
131     """
132     class FaultyPersonTable(PersonTable):
133         missing = tables.Column()
134
135     table = FaultyPersonTable(Person.objects.all())
136     table.as_html()  # the bug would cause this to raise FieldDoesNotExist