Login

Paginator Tag

Author:
insin
Posted:
March 2, 2007
Language:
Python
Version:
Pre .96
Score:
47 (after 51 ratings)

Piggybacks on the pagination-related template context variables provided by the object_list generic view, adding extra context variables for use in displaying links for a given number of pages adjacent to the current page and determining if the first and last pages are included in the displayed links.

Also makes it easy to implement consistent paging all over your site by implementing your pagination controls in a single place - paginator.html.

Optionally accepts a single argument to specify the number of page links adjacent to the current page to be displayed.

Usage:

{% paginator %}

{% paginator 5 %}

 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
from django import template

register = template.Library()

def paginator(context, adjacent_pages=2):
    """
    To be used in conjunction with the object_list generic view.

    Adds pagination context variables for use in displaying first, adjacent and
    last page links in addition to those created by the object_list generic
    view.

    """
    page_numbers = [n for n in \
                    range(context['page'] - adjacent_pages, context['page'] + adjacent_pages + 1) \
                    if n > 0 and n <= context['pages']]
    return {
        'hits': context['hits'],
        'results_per_page': context['results_per_page'],
        'page': context['page'],
        'pages': context['pages'],
        'page_numbers': page_numbers,
        'next': context['next'],
        'previous': context['previous'],
        'has_next': context['has_next'],
        'has_previous': context['has_previous'],
        'show_first': 1 not in page_numbers,
        'show_last': context['pages'] not in page_numbers,
    }

register.inclusion_tag('paginator.html', takes_context=True)(paginator)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 9 months, 4 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

derivin (on March 12, 2007):

VERY COOL! This saved me a bunch of work. I did make a minor change (just a style difference really):

page_numbers = range(max(0, context['page']-adjacent_pages), min(context['pages'], context['page']+adjacent_pages)+1)

#

RichardBronosky (on July 18, 2007):

Oh yea, in that patch I also changed it to use a decorator. I don't know much about python, but I think that is appropriate.

#

RichardBronosky (on July 20, 2007):

I think this is a very important improvement. I hate having to keep adding to the context list as my app matured. I should only have to add new context to my views. So, I came up with this.

To pass the entire context with modifications/additions to the template of an inclusion tag, you can use:

return dict(context.dicts[5], existing_key='val to overwrite old val', new_key='new_val')

#

msurdi (on April 10, 2008):

Could you please post a "view" example for this snippet?

#

romain-hardouin (on June 11, 2008):

Example of a view

def news_by_category(request, category_name, page=1):
    category = get_object_or_404(Category, name__iexact=category_name)
    news = News.objects.select_related(depth=1).filter(category=category.id)

    from django.views.generic import list_detail
    return list_detail.object_list(request,
                               queryset = news,
                               template_name = 'template_name.html',
                               paginate_by = 10,
                               page = page,
                               allow_empty = False,
                               extra_context = {'category': category}
                           )

View parameters and paginator.html?

How this template could be design in order to paginate any resource?

For instance, if you want to paginate instance of News model, then instance of Category model and so forth, links in paginator must be dynamics. Till now I can't figure out how to do this neat and clean.

  • paginator.html -- and thus its template Context -- must be 'view aware' to build links
  • Then, with a paginator template view aware, we can use the template tag {% url %} to generate links
  • Sounds good but this template tag requires view parameters...

So, how transmit those parameters to the template?

#

sugi (on November 14, 2008):

Can you suggest some more examples on using templatetags and how to use URLS for this.

Help me

#

jafo (on October 30, 2009):

I changed the page_numbers so that it would be a bit smarter and include the first page and the last page if it would otherwise include the page or two next to the first or last page. So, instead of getting page_numbers being [2,3,4] or [3,4,5], it would be [1,2,3,4] and [1,2,3,4,5].

I did this for doing flickr (and apparently digg)-like paginators, so you don't get things like [1, '...', 2, 3, 4] or [1, '...', 3 4 5] -- might as well just put a "2" page link in there instead of "...".

Here is the code change I came up with:

startPage = max(context['page'] - adjacent_pages, 1)
if startPage &lt;= 3: startPage = 1
endPage = context['page'] + adjacent_pages + 1
if endPage &gt;= context['pages'] - 1: endPage = context['pages'] + 1
page_numbers = [n for n in range(startPage, endPage) \
        if n > 0 and n &lt;= context['pages']]

So for my paginator.html I use:

<div class="pager">
   {% if has_previous %}
      <span class="page">
      <a href="?page={{ previous }}">&lt; Prev</a>
      </span>
   {% endif %}

   {% if show_first %}
      <span class="page"><a href="?page=1">1</a></span>
      <span class="elipsis">...</span>
   {% endif %}
   {% for linkpage in page_numbers %}
      {% ifequal linkpage page %}
         <span class="current">{{ page }}</span>
      {% else %}
         <span class="page"><a href="?page={{ linkpage }}"
               >{{ linkpage }}</a></span>
      {% endifequal %}
   {% endfor %}
   {% if show_last %}
      <span class="elipsis">...</span>
      <span class="page"><a href="?page=last">{{ pages }}</a></span>
   {% endif %}
   {% if has_next %}
      <span class="page"><a href="?page={{ next }}">Next &gt;</a></span>
   {% endif %}
</div>

Sean

#

jackoder (on April 4, 2010):

Nice work.

#

Placinta (on February 18, 2013):

My version of the paginator function for Django 1.4

def paginator(context, adjacent_pages=2):
    current_page = context['page_obj'].number
    number_of_pages = context['paginator'].num_pages
    page_obj = context['page_obj']
    paginator = context['paginator']
    startPage = max(current_page - adjacent_pages, 1)
    endPage = current_page + adjacent_pages + 1
    if endPage > number_of_pages: endPage = number_of_pages + 1
    page_numbers = [n for n in range(startPage, endPage) \
        if 0 < n <= number_of_pages]

return {
    'page_obj': page_obj,
    'paginator': paginator,
    'page': current_page,
    'pages': number_of_pages,
    'page_numbers': page_numbers,
    'has_previous': page_obj.has_previous(),
    'has_next': page_obj.has_next(),
    'show_first': 1 != current_page,
    'show_last': number_of_pages != current_page,
}

And the corresponding template.

    <span>Page {{ page }} of {{ pages }}</span>
    <ul>
    {% if show_first %}
        <li><a href="?page=1">&laquo; First</a></li>
    {% endif %}
    {% if has_previous %}
        <li><a href="?page={{ page_obj.previous_page_number }}">&lsaquo; Previous</a></li>
    {% endif %}
    {% for one_page in page_numbers %}
        {% ifequal one_page page %}
            <li class="current">{{ page }}</li>
        {% else %}
            <li><a href="?page={{ one_page }}">{{ one_page }}</a></li>
        {% endifequal %}
    {% endfor %}
    {% if has_next %}
        <li><a href="?page={{ page_obj.next_page_number }}">Next &rsaquo;</a></li>
    {% endif %}
    {% if show_last %}
        <li><a href="?page=last">Last &raquo;</a></li>
    {% endif %}

</ul>

#

Juan_1 (on November 22, 2013):

Hello

I have created a paginator model but when I move pages does not show me the link to go back to back

The code is as follows:

<nav> {% If%} entrada.has_previus previous page {% Endif%}

entrada.number Page {{}} of {{entrada.paginator.num_pages}} {% If%} entrada.has_next Next Page {% Endif%} </ nav>

#

Please login first before commenting.