Paginator Tag

 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. Filter to adjust forloop.counter across pages in a paginated view by egmanoj 5 years, 1 month ago
  2. Append paramaters to a GET querystring (template tag) by gregb 4 years, 9 months ago
  3. Simple Paginate by laserlight 10 months, 1 week ago
  4. Paginator TemplateTag by trbs 6 years ago
  5. yet another digg style paginator by akonsu 4 years, 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:

[HTML_REMOVED] {% If%} entrada.has_previus [HTML_REMOVED] previous page [HTML_REMOVED] {% Endif%} [HTML_REMOVED] entrada.number Page {{}} of {{entrada.paginator.num_pages}} [HTML_REMOVED] {% If%} entrada.has_next [HTML_REMOVED] Next Page [HTML_REMOVED] {% Endif%} [HTML_REMOVED]

#

(Forgotten your password?)