diff --git a/django_tables2/paginators.py b/django_tables2/paginators.py index 7132b424..bfabed59 100644 --- a/django_tables2/paginators.py +++ b/django_tables2/paginators.py @@ -56,6 +56,7 @@ class UserListView(SingleTableView): def __init__(self, object_list, per_page, look_ahead=None, **kwargs): self._num_pages = None + self._final_num_pages = None if look_ahead is not None: self.look_ahead = look_ahead @@ -91,8 +92,13 @@ def page(self, number): else: # This is the last page. self._num_pages = number + # For rendering purposes in `table_page_range`, we have to remember the final count + self._final_num_pages = number return Page(objects, number, self) + def is_last_page(self, number): + return number == self._final_num_pages + def _get_count(self): raise NotImplementedError diff --git a/django_tables2/templatetags/django_tables2.py b/django_tables2/templatetags/django_tables2.py index 9dbfcae9..035c83b9 100644 --- a/django_tables2/templatetags/django_tables2.py +++ b/django_tables2/templatetags/django_tables2.py @@ -11,6 +11,7 @@ from django.utils.http import urlencode import django_tables2 as tables +from django_tables2.paginators import LazyPaginator from django_tables2.utils import AttributeDict register = template.Library() @@ -267,6 +268,8 @@ def table_page_range(page, paginator): ret = [1, "..."] + list(ret)[2:] if num_pages not in ret: ret = list(ret)[:-2] + ["...", num_pages] + if isinstance(paginator, LazyPaginator) and not paginator.is_last_page(page.number): + ret.append("...") return ret diff --git a/docs/pages/pagination.rst b/docs/pages/pagination.rst index 1efe5006..1ae52dc6 100644 --- a/docs/pages/pagination.rst +++ b/docs/pages/pagination.rst @@ -32,14 +32,15 @@ set `SingleTableView.table_pagination = False` Lazy pagination ~~~~~~~~~~~~~~~ -The default `~django.core.paginators.Paginator` want to count the number of items, +The default `~django.core.paginators.Paginator` wants to count the number of items, which might be an expensive operation for large QuerySets. In those cases, you can use `.LazyPaginator`, which does not perform a count, -but also does not know what the total amount of pages will be. +but also does not know what the total amount of pages will be, until you've hit +the last page. The `.LazyPaginator` does this by fetching `n + 1` records where the number of records per page is `n`. If it receives `n` or less records, it knows it is on the last page, -preventing rendering of the 'next' button. +preventing rendering of the 'next' button and further "..." ellipsis. Usage with `SingleTableView`:: class UserListView(SingleTableView): diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index 9d525354..e3fadf44 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -286,10 +286,23 @@ def test_table_page_range_num_pages_equals_page_range_plus_one(self): table_page_range(paginator.page(7), paginator), [1, "...", 4, 5, 6, 7, 8, 9, 10, 11] ) - def test_table_page_range_lazy(self): + def test_table_page_range_lazy_beginning(self): paginator = LazyPaginator(range(1, 1000), 10) self.assertEqual(table_page_range(paginator.page(1), paginator), range(1, 3)) + + def test_table_page_range_lazy_middle(self): + paginator = LazyPaginator(range(1, 1000), 10) + self.assertEqual( - table_page_range(paginator.page(10), paginator), [1, "...", 4, 5, 6, 7, 8, 9, 10, 11] + table_page_range(paginator.page(10), paginator), + [1, "...", 4, 5, 6, 7, 8, 9, 10, 11, "..."], + ) + + def test_table_page_range_lazy_last_page(self): + paginator = LazyPaginator(range(1, 1000), 10) + + self.assertEqual( + table_page_range(paginator.page(100), paginator), + [1, "...", 93, 94, 95, 96, 97, 98, 99, 100], )