Fun with Pagination – Back and Ahead by 5

Yesterday I wanted to beef up a ListView-based page with additional navigation controls.  Specifically, I decided to add buttons to jump back 5 and ahead 5 pages in the list.  With a little bit of class extension, this was easy to do.

Source:

from django.core.paginator import Page, Paginator

class PageFive(Page):class PageFive(Page):

    ''' Include info for next 5 and previous 5 pages '''

    def has_next_five(self): 
        return self.number < self.paginator.num_pages - 5 

    def has_previous_five(self): 
        return self.number > 6

    def next_five_page_number(self): 
        return self.paginator.validate_number(self.number + 5)

    def previous_five_page_number(self): 
        return self.paginator.validate_number(self.number - 5)


class PaginatorFive(Paginator):

 ''' Uses the PageFive class to report info for next and previous 5 pages
     Set pageinator_class in ListView to use '''

    def _get_page(self, *args, **kwargs): 
        """ 
        Return an instance of a single page using the PageFive object 
        """ 

        return PageFive(*args, **kwargs)

First step was to extend the Pageclass to add additional methods.  Mimicking the existing methods for next and previous pages, these four new functions return information on the previous five and next five pages of the list.

To use my new PageFiveclass, I also extended the Paginator class.  Lucky for me, the authors have included the _get_page()method as a hook to modify the Pageclass used.  Simple to override.

Next, I have to tell ListViewto call my redefined paginator.  The paginator_classvariable is used to make that change:

class MyListView(ListView):
    model = MyModel
    paginate_by = 10
    paginator_class = PaginatorFive

Finally, I can use the new methods of the PageFiveclass in the template:

<!-- PaginatorFive navigation buttons -->
 {% if is_paginated %}
   <ul class="pagination pagination-centered">
     {% if page_obj.has_previous %}
       <li><a href="?page=1">First</a></li>
       {% if page_obj.has_previous_five %}
         <li><a href="?page={{ page_obj.previous_five_page_number }}">Back 5</a></li>
       {% endif %}
       <li><a href="?page={{ page_obj.previous_page_number }}">Prev</a></li>
    {% endif %}

    <li class="active" ><a href="?page={{page_obj.number}}">{{page_obj.number}} of{{ page_obj.paginator.num_pages }}</a></li>

    {% if page_obj.has_next %}
       <li><a href="?page={{ page_obj.next_page_number }}">Next</a></li>
       {% if page_obj.has_next_five %}
         <li><a href="?page={{ page_obj.next_five_page_number }}">Ahead 5</a></li>
       {% endif %}
       <li><a href="?page={{ page_obj.paginator.num_pages }}">Last</a></li>
     {% endif %}
   </ul>
 {% endif %}

This was a fun little exercise.

 

(Sorry for the word wrap in the code.  Copy to your editor for a better view)