Displaying Page Numbers with django-tables2

Improving on @Serafeim answer (or solving the exercise he left): Here is a pagination block which, using only Django template syntax, renders page numbers that:

  • are enclosed in a <ul> HTML block, whith CSS classes that "play well" with Bootstrap;

  • if there are more than 8 pages, at most 3 pages below and above current page are shown;

  • first and last pages are always shown, with ellipsis between them and the start or end of the range (if needed).

     {% with current_page=table.page.number page_count=table.paginator.num_pages rows_per_page=table.page.object_list|length total_rows=table.page.paginator.count %}
     {% block pagination %}
     <ul class="pagination">
         {% block pagination.allpages %}
             <li class="current">
                 {% blocktrans %}Page {% endblocktrans %}
             </li>
             {% for page in table.paginator.page_range %}
                 {% with range_start=current_page|add:"-3" range_end=current_page|add:"3" page_count_minus_5=page_count|add:"-5" page_count_minus_1=page_count|add:"-1" %}
                     {% if page == current_page %}
                         <li class="active">
                             <span>{{ page }}</span>
                         </li>
                     {% elif page == 1 or page >= range_start and page <= range_end or page == page_count %}
                         <li class="next">
                             <a href="{% querystring table.prefixed_page_field=page %}">{{ page }}</a>
                         </li>
                     {% endif %}
                     {% if page == 1 and current_page > 5 or page == page_count_minus_1 and current_page <= page_count_minus_5 %}
                         <li class="current">...</li>
                     {% endif %}
                 {% endwith %}
             {% endfor %}
         {% endblock pagination.allpages %}
    
         {% block pagination.cardinality %}
             <li class="cardinality">
                 {% if total_rows != rows_per_page %}{% blocktrans %}
                     {{ rows_per_page }} of {{ total_rows }}{% endblocktrans %}
                 {% else %}
                     {{ total_rows }}
                 {% endif %} 
                 {% if total_rows == 1 %}
                     {{ table.data.verbose_name }}
                 {% else %}
                     {{ table.data.verbose_name_plural }}
                 {% endif %}
             </li>
         {% endblock pagination.cardinality %}
     </ul>
     {% endblock pagination %}
     {% endwith %}
    

you need to create a custom page rendering template - you don't need to override any classses.

To do that, start by copying the file

PYTHON\Lib\site-packages\django_tables2\templates\django_tables2\table.html

to the templates directory inside your django application and rename it to mytable.html or whatever else you like.

Now, you need to change the pagination block of that file. There are many ways to do what you like, but a simple way is to add the following lines inside the pagination block (you may remove or keep the other things that are there depending on your specific needs):

{% block pagination.allpages %}
  {% for p in table.paginator.page_range %}
    <a href="{% querystring table.prefixed_page_field=p %}">{{ p }}</a>
  {% endfor %}
{% endblock pagination.allpages %}

Finally, to use your template, just pass your custom template name to the render_table command:

{% load render_table from django_tables2 %}
...
{% render_table table "mytable.html" %}

This is very simple and will give you trouble if you have many pages (so you have to use some ifs to check the number of pages through the table.paginator.num_pages variable). Also, you may highlight the current page and disable the link by using the table.page.number variable.

The above are left as an excersise to the reader :)