Paginación con Django

Mayo 14, 2008

Introducción

Las tareas de paginación son unas de las mas tediosas a la hora de programar un sitio Web. Django incluye herramientas para hacer todo este trabajo de una forma fácil y rápida.

En el siguiente tutorial explicaré un método para realizar paginación de noticias en una aplicación Web.

Este ejemplo esta basado en la version de desarrollo de Django en la fecha de hoy (0.97)

Creando nuestra aplicación

Vamos a suponer que tenemos una aplicación de noticias, la cual posee un modelo para almacenar las mismas:

models.py:

from django.db import models

class Noticias(models.Model):
    Titulo = models.CharField(maxlength=100)
    Cuerpo = models.TextField()
    Fecha_pub = models.DateField('Fecha', auto_now_add=True)
    Imagen = models.ImageField(upload_to= "noticias/%Y/%m/%d", blank=True)

    class Admin:
	list_display = ('Titulo', 'Fecha_pub')

    def  __str__(self):
	return self.Titulo

Para paginar utilizaremos el siguiente módulo de Python el cual puede estar en la raíz de la aplicación y ser incluído en esta con su include correspondiente:

paginator.py

from django.core.paginator import ObjectPaginator, InvalidPage

def Paginador(request, modelo, paginas):
	result_list = Paginator(modelo, paginas)
	try:
		page = int(request.GET.get('page')); #Tomamos el valor de parametro page, usando GET
	except:
		page = 1
	if (page < result_list.page(page)):
		pagina = result_list.page(page)
		Contexto = {'modelo': pagina.object_list, #Asignamos registros de la pagina
			 'page': page, #Pagina Actual
			 'pages': result_list.num_pages, #Cantidad de Paginas
			 'has_next': pagina.has_next(), #True si hay proxima pagina
			 'has_prev': pagina.has_previous(), #true si hay Pagina anterior
			 'next_page': page+1, #Proxima pagina
			 'prev_page': page-1, #Pagina Anterior
			 }
		return Contexto

Este modulo recibe dos argumentos: 1 es un objeto request, 2 un modelo (tabla), en este caso el modelo de las noticias. Como podemos ver la variable resul_list almacenaría solo tres registros de la tabla. “Contexto“ es un diccionario con todos los que nos interesa para realizar el paginado en la plantilla HTML.

También necesitaremos otra pequeña plantilla:

pagination.html:

{% if paginator.has_prev %}
	<a href="/noticias/?page={{ paginator.prev_page }}"><</a>
{% else %}
{% endif %}
Página {{paginator.page}} de {{paginator.pages}}
{% if paginator.has_next %}
	<a href="/noticias/?page={{ paginator.next_page }}">></a>
{% else %}
{% endif %}

Esta plantilla la debemos incluir en la plantilla HTML en la cual realmente queremos realizar el paginado.
Por último la vista que queremos muestre las noticias paginadas debe quedar de la siguiente manera:

views.py:

# importamos el modulo Paginador
from proyecto.Paginador import Paginador

def index(request):
	noticias = Noticias.objects.all().order_by('-Fecha_pub')
	pag = Paginador(request, noticias)
	plantilla = loader.get_template('noticias/noticias_list.html')
	c = RequestContext(request, {'noticia_list': pag['modelo'],
				     'request': request,
				     'paginator': pag,
	return HttpResponse(plantilla.render(c))

La función index es una función común,

  • Primero ordenamos el módulo Noticias por fecha para que se muestren primero las últimas noticias.
  • pag es un objeto del tipo Paginador el cual recibe dos argumentos y devuelve un diccionario.
  • Posteriormente pasamos los datos a la plantilla noticias_list.html
  • pag['modelo'] es el modelo(tabla) noticias con solamente 3 registros. Los que necesitamos.
  • pag es un diccionario con todos los datos necesarios para paginar.

Hasta aquí esta pequeña guía sobre cómo paginar. Espero sea de utilidad al lector, me gustaría recibir algunas opiniones al respecto y de ser posible también sugerencias, esta guía está implementada aquí


Contador de visitantes

Mayo 14, 2008

Introducción

En el siguiente ejemplo crearemos un contador de visitas para tener constancia de las visitas que nuestro sitio recibe. Asumiremos que el lector tiene Django instalado y configurado y que posee conocimientos mínimos sobre el mismo.

Aunque el lenguaje de plantillas de Django incorpora varias etiquetas y filtros, es posible que usted quiera escribir los suyos propios, y es fácil hacerlo.

Creando nuestro propio contador de visitas

Primero, debemos crea un paquete (directorio) “templatetags“ dentro del paquete de la aplicación apropiada. Debería estar en el mismo nivel que “models.py“, “views.py“, etc. Por ejemplo:

visitantes/
    models.py
    templatetags/
    views.py

Añadimos dos ficheros al paquete “templatetags“: un “__init__.py“ (para indicar a Python que es un módulo que contiene código de Python) y un fichero que contendrá las definiciones de sus etiquetas y filtros personalizados llamado “my_tags.py“ (puede nombrarse como usted lo desee) y añadimos lo siguiente a “my_tags.py“:

from django import template
register = template.Library()

def contador(request):
	if request.session.get('contador', False):
		contador = GetContador()
		return str(contador)
	request.session['contador'] = True
	contador = GetContador()
	contador = contador + 1
	SetContador(str(contador))
	return str(contador)

def GetContador():
	f_contador = open('/path/to/contador/contador', 'r')
	contador = f_contador.read()
	return int(contador)

def SetContador(contador):
	'''Funcion que guarda la posición actual del visitante'''
	f_contador = open('/path/to/contador/contador', 'w')
	f_contador.write(contador)
	f_contador.close()

register.simple_tag(contador)

Explicación

  1. Para que sea una biblioteca de etiquetas válida, el módulo debe contener una variable llamada “register“ que sea una instancia de “template.Library“, en la que se registran todas las etiquetas y los filtros.
  2. Definimos la función contador que recibe el parámetro “request“.
  3. Comprobamos la sesión, esto es importante para que el contador no se aumente cuando recargamos la página. En este caso si la sesión existe el contador no se aumentará
  4. Obtenemos el valor del contador a través de la función “GetContador()“
  5. Retornamos el valor del Contador sin aumentar.
  6. Si la sesión no existe la creamos.
  7. Obtenemos el valor del contador a través de la función “GetContador()“
  8. Aumentamos el contador en 1.
  9. Guardamos el valor del contador aumentado en uno en el fichero a través de la función “SetContador()“
  10. Retornamos el valor del contador aumentado en 1.
  11. Definimos la función “GetContador()“
  12. Abrimos el fichero contador en modo sólo lectura.
  13. Leemos el contenido del fichero.
  14. Retornamos el valor
  15. Definimos la función “SetContador()“
  16. Abrimos el fichero contador en modo escritura para añadir el nuevo valor
  17. Escribimos el nuevo valor
  18. Por último cerramos el fichero.
  19. Para facilitar la creación de este tipo de etiquetas, Django proporciona una función de conveniencia, “simple_tag“. Esta función es un método de “django.template.Library“, que toma como argumento una función que a su vez acepta un argumento, la inserta en una función “render“, y la registra en el sistema de plantillas.

Debemos crear el fichero contador en la ubicación /path/to/contador/contador.
Ahora nos vamos a la plantilla donde queremos insertar el contador de vistas e insertamos lo siguiente al inicio de la plantilla:

{% load my_tags %}

La etiqueta {% load %} hace una búsqueda según la opción “INSTALLED_APPS“ y sólo permite la carga de bibliotecas de plantillas pertenecientes a aplicaciones instaladas. Esto es una medida de seguridad: le permite tener el código de muchas librerías de plantillas escritas en Python en un único computador sin habilitar a cada instalación de Django el acceso a todas ellas.
Posteriormente en de la misma plantilla anterior donde queremos que el contador sea visible insertamos lo siguiente:

...
...
<tr>
    <td>
    Visitante #: {% contador request %}
    </td>
</tr>
...
...

“contador“ es el nombre de la función que esta dentro de “my_tags.py“ y debe recibir un parámetro “(request)“ que debe ser pasado a la plantilla para comprobar la sesión y así el contador no será aumentado cuando se recargue la página.

Hasta aquí el contador de visita. No soy un experto en Django, quizás existan otros métodos más fáciles pero este ha sido el que he encontrado. Este contador esta implementado