292 lines
9.9 KiB
Python
292 lines
9.9 KiB
Python
# coding: utf-8
|
|
import six
|
|
import pytest
|
|
|
|
from .app.models import Person, Occupation
|
|
import django_tables2 as tables
|
|
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
|
|
class PersonTable(tables.Table):
|
|
first_name = tables.Column()
|
|
last_name = tables.Column()
|
|
occupation = tables.Column()
|
|
|
|
|
|
def test_boundrows_iteration():
|
|
occupation = Occupation.objects.create(name='Programmer')
|
|
Person.objects.create(first_name='Bradley', last_name='Ayers', occupation=occupation)
|
|
Person.objects.create(first_name='Chris', last_name='Doble', occupation=occupation)
|
|
|
|
table = PersonTable(Person.objects.all())
|
|
records = [row.record for row in table.rows]
|
|
expecteds = Person.objects.all()
|
|
for expected, actual in six.moves.zip(expecteds, records):
|
|
assert expected == actual
|
|
|
|
|
|
def test_model_table():
|
|
"""
|
|
The ``model`` option on a table causes the table to dynamically add columns
|
|
based on the fields.
|
|
"""
|
|
class OccupationTable(tables.Table):
|
|
class Meta:
|
|
model = Occupation
|
|
assert ["id", "name", "region"] == list(OccupationTable.base_columns.keys())
|
|
|
|
class OccupationTable2(tables.Table):
|
|
extra = tables.Column()
|
|
|
|
class Meta:
|
|
model = Occupation
|
|
assert ["id", "name", "region", "extra"] == list(OccupationTable2.base_columns.keys())
|
|
|
|
# be aware here, we already have *models* variable, but we're importing
|
|
# over the top
|
|
from django.db import models
|
|
|
|
class ComplexModel(models.Model):
|
|
char = models.CharField(max_length=200)
|
|
fk = models.ForeignKey("self")
|
|
m2m = models.ManyToManyField("self")
|
|
|
|
class ComplexTable(tables.Table):
|
|
class Meta:
|
|
model = ComplexModel
|
|
assert ["id", "char", "fk"] == list(ComplexTable.base_columns.keys())
|
|
|
|
|
|
def test_mixins():
|
|
class TableMixin(tables.Table):
|
|
extra = tables.Column()
|
|
|
|
class OccupationTable(TableMixin, tables.Table):
|
|
extra2 = tables.Column()
|
|
|
|
class Meta:
|
|
model = Occupation
|
|
assert ["extra", "id", "name", "region", "extra2"] == list(OccupationTable.base_columns.keys())
|
|
|
|
|
|
def test_column_verbose_name():
|
|
"""
|
|
When using queryset data as input for a table, default to using model field
|
|
verbose names rather than an autogenerated string based on the column name.
|
|
|
|
However if a column does explicitly describe a verbose name, it should be
|
|
used.
|
|
"""
|
|
class PersonTable(tables.Table):
|
|
"""
|
|
The test_colX columns are to test that the accessor is used to
|
|
determine the field on the model, rather than the column name.
|
|
"""
|
|
first_name = tables.Column()
|
|
fn1 = tables.Column(accessor='first_name')
|
|
fn2 = tables.Column(accessor='first_name.upper')
|
|
fn3 = tables.Column(accessor='last_name', verbose_name='OVERRIDE')
|
|
last_name = tables.Column()
|
|
ln1 = tables.Column(accessor='last_name')
|
|
ln2 = tables.Column(accessor='last_name.upper')
|
|
ln3 = tables.Column(accessor='last_name', verbose_name='OVERRIDE')
|
|
region = tables.Column(accessor='occupation.region.name')
|
|
r1 = tables.Column(accessor='occupation.region.name')
|
|
r2 = tables.Column(accessor='occupation.region.name.upper')
|
|
r3 = tables.Column(accessor='occupation.region.name', verbose_name='OVERRIDE')
|
|
trans_test = tables.Column()
|
|
trans_test_lazy = tables.Column()
|
|
|
|
# The Person model has a ``first_name`` and ``last_name`` field, but only
|
|
# the ``last_name`` field has an explicit ``verbose_name`` set. This means
|
|
# that we should expect that the two columns that use the ``last_name``
|
|
# field should both use the model's ``last_name`` field's ``verbose_name``,
|
|
# however both fields that use the ``first_name`` field should just use a
|
|
# capitalized version of the column name as the column header.
|
|
table = PersonTable(Person.objects.all())
|
|
# Should be generated (capitalized column name)
|
|
assert 'first name' == table.columns['first_name'].verbose_name
|
|
assert 'first name' == table.columns['fn1'].verbose_name
|
|
assert 'first name' == table.columns['fn2'].verbose_name
|
|
assert 'OVERRIDE' == table.columns['fn3'].verbose_name
|
|
# Should use the model field's verbose_name
|
|
assert 'surname' == table.columns['last_name'].verbose_name
|
|
assert 'surname' == table.columns['ln1'].verbose_name
|
|
assert 'surname' == table.columns['ln2'].verbose_name
|
|
assert 'OVERRIDE' == table.columns['ln3'].verbose_name
|
|
assert 'name' == table.columns['region'].verbose_name
|
|
assert 'name' == table.columns['r1'].verbose_name
|
|
assert 'name' == table.columns['r2'].verbose_name
|
|
assert 'OVERRIDE' == table.columns['r3'].verbose_name
|
|
assert "translation test" == table.columns["trans_test"].verbose_name
|
|
assert "translation test lazy" == table.columns["trans_test_lazy"].verbose_name
|
|
|
|
# -------------------------------------------------------------------------
|
|
|
|
# Now we'll try using a table with Meta.model
|
|
class PersonTable(tables.Table):
|
|
class Meta:
|
|
model = Person
|
|
# Issue #16
|
|
table = PersonTable([])
|
|
assert "translation test" == table.columns["trans_test"].verbose_name
|
|
assert "translation test lazy" == table.columns["trans_test_lazy"].verbose_name
|
|
|
|
|
|
def test_data_verbose_name():
|
|
table = tables.Table(Person.objects.all())
|
|
assert table.data.verbose_name == "person"
|
|
assert table.data.verbose_name_plural == "people"
|
|
|
|
|
|
def test_field_choices_used_to_translated_value():
|
|
"""
|
|
When a model field uses the ``choices`` option, a table should render the
|
|
"pretty" value rather than the database value.
|
|
|
|
See issue #30 for details.
|
|
"""
|
|
LANGUAGES = (
|
|
('en', 'English'),
|
|
('ru', 'Russian'),
|
|
)
|
|
|
|
from django.db import models
|
|
|
|
class Article(models.Model):
|
|
name = models.CharField(max_length=200)
|
|
language = models.CharField(max_length=200, choices=LANGUAGES)
|
|
|
|
def __unicode__(self):
|
|
return self.name
|
|
|
|
class ArticleTable(tables.Table):
|
|
class Meta:
|
|
model = Article
|
|
|
|
table = ArticleTable([Article(name='English article', language='en'),
|
|
Article(name='Russian article', language='ru')])
|
|
|
|
assert 'English' == table.rows[0]['language']
|
|
assert 'Russian' == table.rows[1]['language']
|
|
|
|
|
|
def test_column_mapped_to_nonexistant_field():
|
|
"""
|
|
Issue #9 describes how if a Table has a column that has an accessor that
|
|
targets a non-existent field, a FieldDoesNotExist error is raised.
|
|
"""
|
|
class FaultyPersonTable(PersonTable):
|
|
missing = tables.Column()
|
|
|
|
table = FaultyPersonTable(Person.objects.all())
|
|
table.as_html() # the bug would cause this to raise FieldDoesNotExist
|
|
|
|
|
|
def test_should_support_rendering_multiple_times():
|
|
class MultiRenderTable(tables.Table):
|
|
name = tables.Column()
|
|
|
|
# test queryset data
|
|
table = MultiRenderTable(Person.objects.all())
|
|
assert table.as_html() == table.as_html()
|
|
|
|
|
|
def test_ordering():
|
|
class SimpleTable(tables.Table):
|
|
name = tables.Column(order_by=("first_name", "last_name"))
|
|
|
|
table = SimpleTable(Person.objects.all(), order_by="name")
|
|
assert table.as_html()
|
|
|
|
|
|
def test_fields_should_implicitly_set_sequence():
|
|
class PersonTable(tables.Table):
|
|
extra = tables.Column()
|
|
|
|
class Meta:
|
|
model = Person
|
|
fields = ('last_name', 'first_name')
|
|
table = PersonTable(Person.objects.all())
|
|
assert table.columns.names() == ['last_name', 'first_name', 'extra']
|
|
|
|
|
|
def test_model_properties_should_be_useable_for_columns():
|
|
class PersonTable(tables.Table):
|
|
class Meta:
|
|
model = Person
|
|
fields = ('name', 'first_name')
|
|
|
|
Person.objects.create(first_name='Bradley', last_name='Ayers')
|
|
table = PersonTable(Person.objects.all())
|
|
assert list(table.rows[0]) == ['Bradley Ayers', 'Bradley']
|
|
|
|
|
|
def test_column_with_delete_accessor_shouldnt_delete_records():
|
|
class PersonTable(tables.Table):
|
|
delete = tables.Column()
|
|
|
|
Person.objects.create(first_name='Bradley', last_name='Ayers')
|
|
table = PersonTable(Person.objects.all())
|
|
table.as_html()
|
|
assert Person.objects.get(first_name='Bradley')
|
|
|
|
|
|
def test_order_by_derived_from_queryset():
|
|
queryset = Person.objects.order_by("first_name", "last_name", "-occupation__name")
|
|
|
|
class PersonTable(tables.Table):
|
|
name = tables.Column(order_by=("first_name", "last_name"))
|
|
occupation = tables.Column(order_by=("occupation__name",))
|
|
|
|
assert PersonTable(queryset.order_by("first_name", "last_name", "-occupation__name")).order_by == ("name", "-occupation")
|
|
|
|
class PersonTable(PersonTable):
|
|
class Meta:
|
|
order_by = ("occupation", )
|
|
|
|
assert PersonTable(queryset.all()).order_by == ("occupation", )
|
|
|
|
|
|
def test_queryset_table_data_supports_ordering():
|
|
class Table(tables.Table):
|
|
class Meta:
|
|
model = Person
|
|
|
|
for name in ("Bradley Ayers", "Stevie Armstrong"):
|
|
first_name, last_name = name.split()
|
|
Person.objects.create(first_name=first_name, last_name=last_name)
|
|
|
|
table = Table(Person.objects.all())
|
|
assert table.rows[0]["first_name"] == "Bradley"
|
|
table.order_by = "-first_name"
|
|
assert table.rows[0]["first_name"] == "Stevie"
|
|
|
|
|
|
def test_doesnotexist_from_accessor_should_use_default():
|
|
class Table(tables.Table):
|
|
class Meta:
|
|
model = Person
|
|
default = "abc"
|
|
fields = ("first_name", "last_name", "region")
|
|
|
|
Person.objects.create(first_name="Brad", last_name="Ayers")
|
|
|
|
table = Table(Person.objects.all())
|
|
assert table.rows[0]["first_name"] == "Brad"
|
|
assert table.rows[0]["region"] == "abc"
|
|
|
|
|
|
def test_unicode_field_names():
|
|
class Table(tables.Table):
|
|
class Meta:
|
|
model = Person
|
|
fields = (six.text_type("first_name"),)
|
|
|
|
Person.objects.create(first_name="Brad")
|
|
|
|
table = Table(Person.objects.all())
|
|
assert table.rows[0]["first_name"] == "Brad"
|