Skip to content

Instantly share code, notes, and snippets.

@fmalina
Last active October 3, 2021 19:11
Show Gist options
  • Save fmalina/1192bdabd9709008b689efa257ec4ca5 to your computer and use it in GitHub Desktop.
Save fmalina/1192bdabd9709008b689efa257ec4ca5 to your computer and use it in GitHub Desktop.
Pagination for Django reusable at view level (simple, generic)
"""
Generic pagination reusable at view level.
Paging middleware needs installing in the settings:
MIDDLEWARE = (
... almost at the end...
'paging.paging_middleware',
Use in a view like so:
from paging import simple_paging
def listings(request):
ls = Listing.objects.all()
ls, count, paging = simple_paging(request, ls, 100)
return render(request, 'some_listings.html', {
'ls': ls, 'count': count, 'paging': paging
})
Include paging in your listings template:
{{ paging }}
"""
from django.core.paginator import Paginator, EmptyPage
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
def paging_middleware(get_response):
def middleware(request):
ext = ''
try:
if request.GET.get('page'):
request.page = int(request.GET.get('page', 1))
else:
ext = request.path_info.split('.')[1]
request.page = int(ext)
except IndexError:
request.page = 1
except ValueError: # redirect invalid page numbers to root page
if ext not in ('xml', 'csv'):
return HttpResponseRedirect(request.path_info.split('.')[0])
response = get_response(request)
return response
return middleware
def simple_paging(request, qs, limit, page=None, custom_render=False):
pager = Paginator(qs, limit)
try:
page_obj = pager.page(page or request.page)
qs = page_obj.object_list
except EmptyPage:
page_obj = {}
qs = qs.none()
pages = pager.page_range
count = pager.count
if custom_render:
return qs, count, pages
paginate = render_paging(request, pages, page_obj, count, limit)
return qs, count, paginate
def render_paging(request, pages, page_obj, count, limit):
pages = sample(pages, request.page)
get = request.GET.copy()
get.pop('page', None)
return render_to_string('pagination.html', {
'path': request.path_info.split('/')[-1].split('.')[0],
'mobile': bool(getattr(request, 'mobile', 0)),
'pages': pages,
'page_obj': page_obj,
'page_count': count//limit,
'is_paginated': count > limit,
'getvars': '&' + get.urlencode() if get else ''
})
def sample(pages, current):
"""Show first few, few around the current page & a last page"""
if len(pages) > 20:
ls = []
prev = False
for x in pages:
a = False
if x in range(1, 5)\
or x in range(current-5, current+5)\
or x == pages[-1]:
a = x
if prev or a:
ls.append(a)
prev = a
pages = ls
return pages
# Example pagination.html
"""
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li><a href="{{ path }}{% if page_obj.previous_page_number != 1 %}.{{ page_obj.previous_page_number }}{% endif %}">
<small>◀</small></a>
{% endif %}
{% for page in pages %}
{% if page %}
{% ifequal page page_obj.number %}
<li class="active"><a href="#">{{ page }}</a>
{% else %}
<li><a href="{{ path }}{% if page != 1 %}.{{ page }}{% endif %}">{{ page }}</a>
{% endifequal %}
{% else %}
&hellip;
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li><a href="{{ path }}.{{ page_obj.next_page_number }}"><small>▶</small></a>
{% endif %}
</ul>
{% endif %}
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment