Paginacion en django estilo digg

La Paginación en django es excelente, permite una flexibilidad importante para solucionar muchos problemas que se presentan al paginar resultados, por ejemplo el problema del cacheo, que se presenta al realizar una consulta que pide todos los datos sabiendo que solo vamos a mostrar unos pocos.

Gracias a la excelente documentación podemos encontrar toda la información aquí: http://docs.djangoproject.com/en/1.1/topics/pagination/#topics-pagination

Sin embargo, cuando se trabajan volúmenes grandes de información, digamos mas de 50 paginas, se hace dispendioso pasar entre paginas hasta llegar a la que buscamos, por eso es muy útil tener una paginación al estilo Digg que muestra algunas paginas adicionales y no solo el enlace a la anterior y la siguiente.

Tomando como base este excelente trabajo: http://krisje8.com/blog/2009/jul/02/django-pagination-template-tag-digg-style/ realice algunas modificaciones para que muestre ‘…’ entre las paginas iniciales y la pagina actual, para darle una mejor ubicación al usuario sobre donde se encuentra.

Tenemos el siguiente template_tag:

#! /usr/bin/env python
# -*- coding: utf8 -*-
# render_paginator.py
from django.template import Library
 
register = Library()
 
def render_paginator(context, first_last_amount=2, before_after_amount=4):
    page_obj = context['page_obj']
    paginator = context['paginator']
    page_numbers = []
 
    # Pages before current page
    if page_obj.number > first_last_amount + before_after_amount:
        for i in range(1, first_last_amount + 1):
            page_numbers.append(i)
 
        page_numbers.append(None)
 
        for i in range(page_obj.number - before_after_amount, page_obj.number):
            page_numbers.append(i)
 
    else:
        for i in range(1, page_obj.number):
            page_numbers.append(i)
 
    # Current page and pages after current page
    if page_obj.number + first_last_amount + before_after_amount < paginator.num_pages:
        for i in range(page_obj.number, page_obj.number + before_after_amount + 1):
            page_numbers.append(i)
 
        page_numbers.append(None)
 
        for i in range(paginator.num_pages - first_last_amount + 1, paginator.num_pages + 1):
            page_numbers.append(i)
 
    else:
        for i in range(page_obj.number, paginator.num_pages + 1):
            page_numbers.append(i)
 
    return {
        'paginator': paginator,
        'page_obj': page_obj,
        'page_numbers': page_numbers
    }
 
register.inclusion_tag('layout/pagination.html', takes_context=True)(render_paginator)

Con la siguiente plantilla:

{% if page_obj.has_previous %}
  <a href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for page in page_numbers %}
  {% if page %}
    {% ifequal page page_obj.number %}
      <strong>{{ page }}</strong>
    {% else %}
      <a href="?page={{ page }}">{{ page }}</a>
    {% endifequal %}
  {% else %}
    ...
  {% endif %}
{% endfor %}
{% if page_obj.has_next %}
  <a href="?page={{ page_obj.next_page_number }}">Next</a>
{% endif %}

Para usarlo se coloca el siguiente codigo en cualquiera de las plantillas que queramos paginar:

    {% if is_paginated %}
      {% load render_paginator %}
      {% render_paginator 2 3 %}
    {% endif %}

Lo que genera un código como:

Previous  1  2  ... 5  6  7  8  9  10  11  ... 25  26  Next

Lo mejor de todo es que no necesita ningún componente adicional ni interfiere con la paginación por defecto que traen las vistas genéricas en django.

Tags: , ,

8 De respuestas a “Paginacion en django estilo digg”

  1. Vinicius Salsotto 29 enero, 2010 en 11:21 PM #

    Hi, I’m having trouble!
    I can not make it work, let me show you did with:

    I added the file correctly render_paginator the directory ‘templatetags’.

    consultoria.urls My file looks like this:
    url (r ‘^ interest / (? P [\ w-]+)/(? P \ d +)/$’,’ category ‘, name =’ category ‘),

    My View:
    def category (request, slug = None, page = None, 2 = paginate_by, allow_empty = True):

    get_object_or_404 category = (Category, ** ( ‘slug’: slug))
    imoveis = Imovel.objects.filter (**{‘ category ‘: categoria.id)). order_by (‘-date ‘)

    paginator = Paginator (real estate, paginate_by, allow_empty_first_page = allow_empty)

    if page == None:
    page = request.GET.get ( ‘page’, 1)

    try:
    page = int (page)
    except ValueError:
    raise Http404

    page_obj = paginator.page (page)

    context = Context ()
    context [ 'object_list'] = page_obj.object_list
    context [ 'paginator'] = paginator
    context [ 'page_obj'] = page_obj

    return render_to_response ( ‘consulting / categorias.html’, context, context_instance = RequestContext (request))

    The template is in the directory of templates, and template where you want to do pagination is as follows:
    (% Load%) render_paginator
    (% If%) is_paginated
    Render_paginator (% 1 3%)
    (% Endif%)

    Thanks!

  2. Camilo Nova 30 enero, 2010 en 7:27 AM #

    First: Make sure the name of the app you have the templatetag is on your settings
    Second: The other pagination method works for you?
    Third: Did you have the template ‘layout/pagination.html’ ?

    Let me know

  3. Roylan 31 mayo, 2010 en 9:35 AM #

    HOla

    Queremos implementar este paginado pero no funciona, creo que falta explicar si se debe hacer algo en la vista que se va a realizar este paginado.

    salu2
    roylan

  4. Carlos 24 agosto, 2010 en 12:09 PM #

    Sin duda un poco mas de esplicacion no estaria mal para los principiantes

  5. Camilo Nova 24 agosto, 2010 en 12:11 PM #

    Por favor publiquen sus errores o la parte que no entienden para como la solucionamos.

  6. francisco A. 2 diciembre, 2010 en 1:42 PM #

    sin lugar a duda creo que algo falta en la explicacion, lo integre pero no funciono

  7. Camilo Nova 2 diciembre, 2010 en 4:52 PM #

    Pero publiquen los errores a ver como podemos ayudar!

  8. The Lawnmower Man 23 enero, 2012 en 8:33 AM #

    Funciona perfectamente. Como hay gente con problemas, que sepan que solo hace falta tener en cuenta:

    1) En el código del templatetag, cambiar “<” y “>” por “”, respectivamente.
    2) En la vista, proporcionar las dos instancias de objeto que requiere el “templatetag”:
    return render_to_response(‘plantilla.html’, {‘page_obj’:page_obj, ‘paginator’:paginator})

    Muchas gracias Camilo, con diferencia el mejor tutorial para este problema que he encontrado en Internet.

Deja una respuesta