If you’re paginating your data and have tens or hundreds of pages, chances are you’d prefer only a subset of these be displayed in your page number list (example – see page list at bottom). Django-paginator gets 90% of your work done for you however it doesn’t support this one very useful feature. To make a developers life easier, meet flynsarmy_paginator!
Download it here.
This app is a simple subclass of django’s built in Paginator and Page classes. The only changes I’ve made are to add an optional adjacent_pages parameter to FlynsarmyPaginator and a .page_range_data variable to the FlynsarmyPage object with the following contents:
- page_range – same as Paginator.page_range – a list of page numbers but only showing a subset of pages if adjacent_pages was specified in the FlynsarmyPaginator constructor.
- show_first – Boolean value set to True if ‘1’ isn’t present in the page_range list above.
- show_last – Boolean vlaue set to True if the last page isn’t present in the page_range list above.
Usage
Add to your INSTALLED_APPS in settings.py:
1 2 3 4 5 6 | INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', ..., 'flynsarmy_paginator', ) |
An example view (taken mostly from the docs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from django.core.paginator import EmptyPage, PageNotAnIntegerfrom flynsarmy_paginator.paginator import FlynsarmyPaginator def listing(request): contact_list = Contacts.objects.all() paginator = Paginator(contact_list, 25, adjacent_objects=6) # Show 25 contacts per page page = request.GET.get('page') try: contacts = paginator.page(page) except PageNotAnInteger: # If page is not an integer, deliver first page. contacts = paginator.page(1) except EmptyPage: # If page is out of range (e.g. 9999), deliver last page of results. contacts = paginator.page(paginator.num_pages) return render_to_response('list.html', {"contacts": contacts}) |
and template:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | {% for contact in contacts %} {# Each "contact" is a Contact model object. #} {{ contact.full_name|upper }}<br /> ... {% endfor %} <div class="pagination"> <span class="step-links"> {% if contacts.has_previous %} <a href="?page={{ contacts.previous_page_number }}">previous</a> {% endif %} {% if contacts.page_range_data.show_first %} <a href="?page=1">1</a> <span class="ellipsis">...</span> {% endif %} {% for i in contacts.page_range_data.page_range %} {% ifequal i contacts.number %} {{ i }} {% else %} <a href="?page={{ i }}">{{ i }}</a> {% endifequal %} {% endfor %} {% if contacts.page_range_data.show_last %} <span class="ellipsis">...</span> <a href="?page={{ contacts.paginator.num_pages }}">{{ contacts.paginator.num_pages }}</a> {% endif %} {% if contacts.has_next %} <a href="?page={{ contacts.next_page_number }}">next</a> {% endif %} </span> </div> |
I’d like to give a big thanks to the people of tummy.com for writing most of the logic behind the .page_range_data.page_range function so I didn’t have to!