Login

Digg-style pagination, and retain GET params

Author:
hanson2010
Posted:
June 3, 2012
Language:
Python
Version:
1.3
Tags:
pagination
Score:
1 (after 1 ratings)

This snipplet is based on Ryan Kanno's work and snipplet #2680.

The page numbers are basically composed by pages_outside_trailing_range, page_range and pages_outside_leading_range.

The GET params in the request(except for page itself) are retained across different pages. This is important when you have an order_by param working inline.

  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
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
# -*- coding: utf-8 -*-

'''
Based on http://blog.localkinegrinds.com/2007/09/06/digg-style-pagination-in-django/
         and http://djangosnippets.org/snippets/2680/

Recreated by Haisheng HU <hanson2010@gmail.com> on Jun 3, 2012
'''

from django import template

register = template.Library()

LEADING_PAGE_RANGE_DISPLAYED = TRAILING_PAGE_RANGE_DISPLAYED = 10
LEADING_PAGE_RANGE = TRAILING_PAGE_RANGE = 8
NUM_PAGES_OUTSIDE_RANGE = 2 
ADJACENT_PAGES = 4

def digg_paginator(context):
    '''
    To be used in conjunction with the object_list generic view.

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

    paginator = context['paginator']
    page_obj = context['page_obj']
    pages = paginator.num_pages
    page = page_obj.number
    in_leading_range = in_trailing_range = False
    pages_outside_leading_range = pages_outside_trailing_range = range(0)
    if pages <= LEADING_PAGE_RANGE_DISPLAYED + NUM_PAGES_OUTSIDE_RANGE + 1:
        in_leading_range = in_trailing_range = True
        page_range = [n for n in range(1, pages + 1)]
    elif page <= LEADING_PAGE_RANGE:
        in_leading_range = True
        page_range = [n for n in range(1, LEADING_PAGE_RANGE_DISPLAYED + 1)]
        pages_outside_leading_range = [n + pages for n in range(0, -NUM_PAGES_OUTSIDE_RANGE, -1)]
    elif page > pages - TRAILING_PAGE_RANGE:
        in_trailing_range = True
        page_range = [n for n in range(pages - TRAILING_PAGE_RANGE_DISPLAYED + 1, pages + 1) if n > 0 and n <= pages]
        pages_outside_trailing_range = [n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]
    else: 
        page_range = [n for n in range(page - ADJACENT_PAGES, page + ADJACENT_PAGES + 1) if n > 0 and n <= pages]
        pages_outside_leading_range = [n + pages for n in range(0, -NUM_PAGES_OUTSIDE_RANGE, -1)]
        pages_outside_trailing_range = [n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]

    # Now try to retain GET params, except for 'page'
    # Add 'django.core.context_processors.request' to settings.TEMPLATE_CONTEXT_PROCESSORS beforehand
    request = context['request']
    params = request.GET.copy()        
    if 'page' in params:
        del(params['page'])
    get_params = params.urlencode()

    return {
        'pages': pages,
        'page': page,
        'previous': page_obj.previous_page_number(),
        'next': page_obj.next_page_number(),
        'has_previous': page_obj.has_previous(),
        'has_next': page_obj.has_next(),
        'page_range': page_range,
        'in_leading_range': in_leading_range,
        'in_trailing_range': in_trailing_range,
        'pages_outside_leading_range': pages_outside_leading_range,
        'pages_outside_trailing_range': pages_outside_trailing_range,
        'get_params': get_params,
    }
 
register.inclusion_tag("digg_paginator.html", takes_context=True)(digg_paginator)

'''
Create digg_paginator.html in template folder as below. Then you can remix it and shine it by CSS.

{% spaceless %}
  {% if has_previous %}
    <li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}page={{ previous }}">&laquo; Prev</a></li>
  {% endif %}
  {% if not in_leading_range %}
    {% for p in pages_outside_trailing_range %}
      <li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}page={{ p }}">{{ p }}</a></li>
    {% endfor %}
    <li><span class="ellipsis">...</span></li>
  {% endif %}
  {% for p in page_range %}
    {% if p == page %}
      <li><span class="active">{{ p }}</span></li>
    {% else %}
      <li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}page={{ p }}">{{ p }}</a></li>
    {% endif %}
  {% endfor %}
  {% if not in_trailing_range %}
    <li><span class="ellipsis">...</span></li>
    {% for p in pages_outside_leading_range reversed %}
      <li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}page={{ p }}">{{ p }}</a></li>
    {% endfor %}
  {% endif %}
  {% if has_next %}
    <li><a href="{% if get_params %}?{{ get_params }}&{% else %}?{% endif %}page={{ next }}">Next &raquo;</a></li>
  {% endif %}
{% endspaceless %}
'''

More like this

  1. Stateful paginator, digg style by miracle2k 7 years, 2 months ago
  2. Pretty Paginator Tag by sbaechler 3 years, 3 months ago
  3. yet another digg style paginator by akonsu 5 years, 7 months ago
  4. Digg-like paginator, updated by miracle2k 7 years ago
  5. Improved many-page pagination by dokterbob 4 years, 8 months ago

Comments

sbaechler (on May 23, 2013):

I updated the template for use with Foundation: Gist

#

Please login first before commenting.