Reputation: 1822
I have implemented a paginator with the generic ListView. My problem is that for list with many pages it displays all the page numbers instead of for example five pages before and after the current page. Is there an easy way to fix this?
in the views.py:
class CarList(LoginRequiredMixin, ListView):
model = Car
paginate_by = 20
in the html:
{% if is_paginated %}
<ul class="pagination pagination-centered">
{% if page_obj.has_previous %}
<li><a href="/car?ordering={{ current_order }}&page=1"><<</a></li>
<li><a href="/car?ordering={{ current_order }}&page={{ page_obj.previous_page_number }}"><</a></li>
{% endif %}
{% for i in paginator.page_range %}
<li {% if page_obj.number == i %} class="active" {% endif %}><a href="/car?ordering={{ current_order }}&page={{i}}">{{i}}</a></li>
{% endfor %}
{% if page_obj.has_next %}
<li><a href="/car?ordering={{ current_order }}&page={{ page_obj.next_page_number }}">></a></li>
<li><a href="/car?ordering={{ current_order }}&page={{ page_obj.paginator.num_pages }}">>></a></li>
{% endif %}
</ul>
{% endif %}
Upvotes: 6
Views: 4196
Reputation: 4068
The algorithm for that is not too complicated, and can be further simplified if we assume that if there are more than 11 pages (current, 5 before, 5 after) we are always going to show 11 links. Now we have 4 cases:
With the above in mind, let's modify your view, create a variable to hold the numbers of pages to show and put it in the context:
class CarList(LoginRequiredMixin, ListView):
model = Car
paginate_by = 20
def get_context_data(self, **kwargs):
context = super(CarList, self).get_context_data(**kwargs)
if not context.get('is_paginated', False):
return context
paginator = context.get('paginator')
num_pages = paginator.num_pages
current_page = context.get('page_obj')
page_no = current_page.number
if num_pages <= 11 or page_no <= 6: # case 1 and 2
pages = [x for x in range(1, min(num_pages + 1, 12))]
elif page_no > num_pages - 6: # case 4
pages = [x for x in range(num_pages - 10, num_pages + 1)]
else: # case 3
pages = [x for x in range(page_no - 5, page_no + 6)]
context.update({'pages': pages})
return context
Now you can simply use the new variable in your template to create page links:
(...)
{% for i in pages %}
<li {% if page_obj.number == i %} class="active" {% endif %}><a href="/car?ordering={{ current_order }}&page={{i}}">{{i}}</a></li>
{% endfor %}
(...)
Upvotes: 12