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 %}
Additionally, switching to keyset pagination will improve the performance of page lookups and make them work in constant time. Django makes it easy to alter its default configuration, giving you the power to build a performant solution for pagination in Django.
Example. Note that you can give Paginator a list/tuple, a Django QuerySet , or any other object with a count() or __len__() method. When determining the number of objects contained in the passed object, Paginator will first try calling count() , then fallback to using len() if the passed object has no count() method.
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 %}
(...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With