Add cardinality to the pagination display, resolves #94
This commit is contained in:
parent
38bfda136d
commit
9effe9efe8
|
@ -89,6 +89,7 @@ v0.12.0
|
|||
- Accessor's now honor ``alters_data`` during resolving. Fixes issue that would
|
||||
delete all your data when a column had an accessor of ``delete``
|
||||
- Add ``default`` and ``value`` to context of ``TemplateColumn``
|
||||
- Add cardinality indication to the pagination area of a table
|
||||
|
||||
v0.11.0
|
||||
-------
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
# coding: utf-8
|
||||
from .tables import Table
|
||||
from .columns import (Column, CheckBoxColumn, DateColumn, DateTimeColumn,
|
||||
LinkColumn, TemplateColumn, EmailColumn, URLColumn)
|
||||
from .config import RequestConfig
|
||||
from .utils import A, Attrs
|
||||
from .views import SingleTableMixin, SingleTableView
|
||||
# pylint: disable=W0611
|
||||
from .tables import Table
|
||||
from .columns import (BooleanColumn, Column, CheckBoxColumn, DateColumn,
|
||||
DateTimeColumn, LinkColumn, TemplateColumn, EmailColumn,
|
||||
URLColumn)
|
||||
from .config import RequestConfig
|
||||
from .utils import A, Attrs
|
||||
from .views import SingleTableMixin, SingleTableView
|
||||
|
||||
|
||||
__version__ = "0.11.0"
|
||||
|
|
|
@ -88,6 +88,10 @@ table.paleblue + ul.pagination > li:first-child {
|
|||
margin-left: 0;
|
||||
}
|
||||
|
||||
table.paleblue + ul.pagination > li.cardinality {
|
||||
float: right;
|
||||
}
|
||||
|
||||
table.paleblue > tbody > tr > td > span.true,
|
||||
table.paleblue > tbody > tr > td > span.false {
|
||||
background-position: top left;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# coding: utf-8
|
||||
import copy
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.utils.datastructures import SortedDict
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import get_template
|
||||
from django.utils.encoding import StrAndUnicode
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import get_template
|
||||
from django.utils.encoding import StrAndUnicode
|
||||
import warnings
|
||||
from .utils import (Accessor, AttributeDict, OrderBy, OrderByTuple, segment,
|
||||
Sequence)
|
||||
from .rows import BoundRows
|
||||
from . import columns
|
||||
from .utils import (Accessor, AttributeDict, cached_property, OrderBy,
|
||||
OrderByTuple, segment, Sequence)
|
||||
from .rows import BoundRows
|
||||
from . import columns
|
||||
|
||||
|
||||
QUERYSET_ACCESSOR_SEPARATOR = '__'
|
||||
|
@ -114,6 +114,30 @@ class TableData(object):
|
|||
"""
|
||||
return self.data[key]
|
||||
|
||||
@cached_property
|
||||
def verbose_name(self):
|
||||
"""
|
||||
The full (singular) name for the data.
|
||||
|
||||
Queryset data has its model's ``Meta.verbose_name`` honored. List data
|
||||
is checked for a ``verbose_name`` attribute, and falls back to using
|
||||
``"item"``.
|
||||
"""
|
||||
if hasattr(self, "queryset"):
|
||||
return self.queryset.model._meta.verbose_name
|
||||
return getattr(self.list, "verbose_name", "item")
|
||||
|
||||
@cached_property
|
||||
def verbose_name_plural(self):
|
||||
"""
|
||||
The full (plural) name of the data.
|
||||
|
||||
This uses the same approach as ``verbose_name``.
|
||||
"""
|
||||
if hasattr(self, "queryset"):
|
||||
return self.queryset.model._meta.verbose_name_plural
|
||||
return getattr(self.list, "verbose_name_plural", "items")
|
||||
|
||||
|
||||
class DeclarativeColumnsMetaclass(type):
|
||||
"""
|
||||
|
|
|
@ -47,19 +47,27 @@
|
|||
{% endblock table %}
|
||||
|
||||
{% if table.page %}
|
||||
{% with table.page.paginator.count as total %}
|
||||
{% with table.page|length as count %}
|
||||
{% block pagination %}
|
||||
<ul class="pagination">
|
||||
{% if table.page.has_previous %}
|
||||
{% nospaceless %}{% block pagination.previous %}<li class="previous"><a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">{% trans "Previous" %}</a></li>{% endblock pagination.previous %}{% endnospaceless %}
|
||||
{% endif %}
|
||||
|
||||
{% if table.page.has_previous or table.page.has_next %}
|
||||
{% nospaceless %}{% block pagination.current %}<li class="current">{% blocktrans with current=table.page.number total=table.paginator.num_pages %}Page {{ current }} of {{ total }}{% endblocktrans %}</li>{% endblock pagination.current %}{% endnospaceless %}
|
||||
{% endif %}
|
||||
|
||||
{% if table.page.has_next %}
|
||||
{% nospaceless %}{% block pagination.next %}<li class="next"><a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">{% trans "Next" %}</a></li>{% endblock pagination.next %}{% endnospaceless %}
|
||||
{% endif %}
|
||||
|
||||
{% nospaceless %}{% block pagination.cardinality %}<li class="cardinality">{% if total != count %}{{ table.page|length }} of {% endif %}{{ total }} {% if total == 1 %}{{ table.data.verbose_name }}{% else %}{{ table.data.verbose_name_plural }}{% endif %}</li>{% endblock pagination.cardinality %}{% endnospaceless %}
|
||||
</ul>
|
||||
{% endblock pagination %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
|
|
|
@ -401,3 +401,18 @@ def segment(sequence, aliases):
|
|||
continue
|
||||
else:
|
||||
yield [valias]
|
||||
|
||||
|
||||
class cached_property(object):
|
||||
"""
|
||||
Decorator that creates converts a method with a single
|
||||
self argument into a property cached on the instance.
|
||||
|
||||
Taken directly from Django 1.4.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
||||
def __get__(self, instance, type):
|
||||
res = instance.__dict__[self.func.__name__] = self.func(instance)
|
||||
return res
|
||||
|
|
|
@ -3,4 +3,6 @@ from django.contrib import admin
|
|||
from .models import Country
|
||||
|
||||
|
||||
admin.site.register(Country)
|
||||
class CountryAdmin(admin.ModelAdmin):
|
||||
list_per_page = 2
|
||||
admin.site.register(Country, CountryAdmin)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -6,13 +7,13 @@ from django.utils.translation import ugettext_lazy as _
|
|||
class Country(models.Model):
|
||||
"""Represents a geographical Country"""
|
||||
name = models.CharField(max_length=100)
|
||||
population = models.PositiveIntegerField(verbose_name=u"Población")
|
||||
population = models.PositiveIntegerField(verbose_name="población")
|
||||
tz = models.CharField(max_length=50)
|
||||
visits = models.PositiveIntegerField()
|
||||
commonwealth = models.NullBooleanField()
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = _("Countries")
|
||||
verbose_name_plural = _("countries")
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
|
|
@ -25,6 +25,10 @@ class Person(models.Model):
|
|||
safe = models.CharField(
|
||||
max_length=200, blank=True, verbose_name=mark_safe("<b>Safe</b>"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = "person"
|
||||
verbose_name_plural = "people"
|
||||
|
||||
def __unicode__(self):
|
||||
return self.first_name
|
||||
|
||||
|
|
|
@ -113,6 +113,13 @@ def attrs():
|
|||
assert {"c": "d"} == TestTable4([], attrs={"c": "d"}).attrs
|
||||
|
||||
|
||||
@core.test
|
||||
def data_knows_its_name():
|
||||
table = tables.Table([{}])
|
||||
assert table.data.verbose_name == "item"
|
||||
assert table.data.verbose_name_plural == "items"
|
||||
|
||||
|
||||
@core.test
|
||||
def datasource_untouched():
|
||||
"""Ensure that data that is provided to the table (the datasource) is not
|
||||
|
|
|
@ -76,7 +76,7 @@ def mixins():
|
|||
|
||||
|
||||
@models.test
|
||||
def verbose_name():
|
||||
def 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.
|
||||
|
@ -140,6 +140,13 @@ def verbose_name():
|
|||
assert "translation test lazy" == table.columns["trans_test_lazy"].verbose_name
|
||||
|
||||
|
||||
@models.test
|
||||
def data_verbose_name():
|
||||
table = tables.Table(Person.objects.all())
|
||||
assert table.data.verbose_name == "person"
|
||||
assert table.data.verbose_name_plural == "people"
|
||||
|
||||
|
||||
@models.test
|
||||
def field_choices_used_to_translated_value():
|
||||
"""
|
||||
|
|
|
@ -108,15 +108,18 @@ def custom_rendering():
|
|||
@templates.test
|
||||
def render_table_templatetag():
|
||||
# ensure it works with a multi-order-by
|
||||
request = factory.get('/')
|
||||
table = CountryTable(MEMORY_DATA, order_by=('name', 'population'))
|
||||
RequestConfig(request).configure(table)
|
||||
template = Template('{% load django_tables2 %}{% render_table table %}')
|
||||
html = template.render(Context({'request': factory.get('/'), 'table': table}))
|
||||
html = template.render(Context({'request': request, 'table': table}))
|
||||
|
||||
root = parse(html)
|
||||
assert len(root.findall('.//thead/tr')) == 1
|
||||
assert len(root.findall('.//thead/tr/th')) == 4
|
||||
assert len(root.findall('.//tbody/tr')) == 4
|
||||
assert len(root.findall('.//tbody/tr/td')) == 16
|
||||
assert root.find('ul[@class="pagination"]/li[@class="cardinality"]').text == '4 items'
|
||||
|
||||
# no data with no empty_text
|
||||
table = CountryTable([])
|
||||
|
@ -128,9 +131,11 @@ def render_table_templatetag():
|
|||
assert len(root.findall('.//tbody/tr')) == 0
|
||||
|
||||
# no data WITH empty_text
|
||||
request = factory.get('/')
|
||||
table = CountryTable([], empty_text='this table is empty')
|
||||
RequestConfig(request).configure(table)
|
||||
template = Template('{% load django_tables2 %}{% render_table table %}')
|
||||
html = template.render(Context({'request': factory.get('/'), 'table': table}))
|
||||
html = template.render(Context({'request': request, 'table': table}))
|
||||
root = parse(html)
|
||||
assert len(root.findall('.//thead/tr')) == 1
|
||||
assert len(root.findall('.//thead/tr/th')) == 4
|
||||
|
|
Loading…
Reference in New Issue