6

There is new option to create pagination range - get_elided_page_range https://docs.djangoproject.com/en/3.2/ref/paginator/#django.core.paginator.Paginator.get_elided_page_range

How should I use it? How can I set args? I am using CBV ListView. I tried https://nemecek.be/blog/105/how-to-use-elided-pagination-in-django-and-solve-too-many-pages-problem but it didn't work for me.

I have 81 pages and current page is 10. Problem is I am always have range 1 2 3 4 ... 80 81 What am I doing wrong?

#views.py

class TrailersListView(ListView):
    queryset = Trailer.objects.all()
    paginate_by = 10

#template.html

{% for i in paginator.get_elided_page_range %}
    {% if page_obj.number == i %}
        <li class="active page-item">
            <span class="page-link">{{ i }}</span>
        </li>
    {% else %}
        {% if i == paginator.ELLIPSIS %}
            <li class="page-item">
                <span class="page-link">{{ paginator.ELLIPSIS }}</span>
            </li>
        {% else %}
            <li class="page-item">
                <a class="page-link" href="?page={{ i }}">{{ i }}</a>
            </li>
        {% endif %}
    {% endif %}
{% endfor %}
Vadim Beglov
  • 343
  • 1
  • 4
  • 15

2 Answers2

16

The page number is not passed to the "get_elided_page_range" method and it uses the default value (1) all the time. So I created a custom tag to pass it a number.

appname/templatetags/paginator_tags.py

from django import template
from django.core.paginator import Paginator

register = template.Library()


@register.simple_tag
def get_proper_elided_page_range(p, number, on_each_side=3, on_ends=2):
    paginator = Paginator(p.object_list, p.per_page)
    return paginator.get_elided_page_range(number=number, 
                                           on_each_side=on_each_side,
                                           on_ends=on_ends)

template.html

{% load paginator_tags %}

{% get_proper_elided_page_range paginator page_obj.number as page_range %} <!-- here -->
{% for i in page_range %}
    {% if page_obj.number == i %}
        <li class="active page-item">
            <span class="page-link">{{ i }}</span>
        </li>
    {% else %}
        {% if i == paginator.ELLIPSIS %}
            <li class="page-item">
                <span class="page-link">{{ paginator.ELLIPSIS }}</span>
            </li>
        {% else %}
            <li class="page-item">
                <a class="page-link" href="?page={{ i }}">{{ i }}</a>
            </li>
        {% endif %}
    {% endif %}
{% endfor %}

working paginator

You can add additional arguments, e.g:

{% get_proper_elided_page_range paginator page_obj.number 1 1 as page_range %}

paginator example with arguments

Moses Machua
  • 11,245
  • 3
  • 36
  • 50
Cous
  • 198
  • 1
  • 7
3

If you are using a class-based view such as ListView in the question's example, then if you trigger pagination by setting the paginate_by member, the page_obj object is available in the get_context_data method. From this method, you can invoke get_elided_page_range on the Paginator to set extra context for the template being rendered.

Example:

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data(**kwargs)
        page: Page = context['page_obj']
        context['paginator_range'] = page.paginator.get_elided_page_range(page.number)
        return context

You can then access paginator_range from within your template.


Usage note: this method returns a generator which yields either an int (which is a valid page number) or a str (…), which is not.

Brett
  • 4,341
  • 2
  • 19
  • 17