El templatetag {% regroup %} del lenguaje de plantillas de Django nos permite agrupar un listado de objetos por una propiedad. Generalmente utilizamos un campo por el que agrupar pero también podemos utilizar una función propia para agrupar los objetos como queramos.
Vamos a ver un ejemplo sencillo en el que agruparemos un listado de artículos por su fecha de publicación, dividiéndolos en artículos publicados "Esta semana", "La semana pasada" y "Hace X semanas". El siguiente models.py tiene un modelo Articulo con una fecha de publicación que nos servirá para hacer la agrupación. La función semana_group del modelo nos permitirá separar los artículos en grupos distintos según la diferencia de días entre hoy y la fecha de publicación de cada artículo:
from django.db import models
import datetime
class Articulo(models.Model):
titulo = models.CharField(max_length=250)
fecha = models.DateField()
def semana_group(self):
hoy = datetime.date.today()
dias = (hoy - self.fecha).days
if dias <= 7:
group = 'Esta semana'
elif dias <= 14:
group = 'La semana pasada'
else:
group = 'Hace %s semanas' % str(dias/7)
return group
En nuestra vista nos bastaría con listar todos los artículos o filtrar por cualquier atributo. Por ejemplo:
articulos = Articulo.objects.all()
Y en nuestra plantilla es donde utilizaremos el templatetag {% regroup %} agrupando el listado de artículos por el método semana_group que hemos añadido al modelo:
{% regroup articulos by semana_group as articulos_por_semana %}
{% for articulos in articulos_por_semana %}
<h2>{{ articulos.grouper }}</h2>
<ul>
{% for articulo in articulos.list %}
<li>{{ articulo.titulo }}</li>
{% endfor %}
</ul>
{% endfor %}
Publicado por Antonio Melé el Sábado 21 d Agosto d 2010 | 5 comentarios | Categorías: modelos, plantillas, trucos
Vamos a ver cómo combinar django-qsstats para generar estadísticas y Google Visualization API para representarlas gráficamente.
django-qsstats permite obtener estadísticas agregadas sobre querysets de forma sencilla. Vamos a crear una vista que nos dé el número de usuarios registrados cada día para los últimos 14 días. Para ello crearemos una QuerySetStats a partir del campo date_joined del modelo User de django.contrib.auth. Usaremos time_series pasándole la fecha inicial y final, para obtener un listado de tuplas tipo (fecha, valor) diario con la fecha y el número de usuarios registrados cada día. Necesitaremos pasar a nuestra plantilla nuestra clave de la API de javascript de Google. Si no tienes una clave puedes conseguirla aquí.
Crearemos la siguiente vista en views.py:
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib.auth import User
import datetime
import qsstats
def estadisticas(request):
GOOGLE_API_KEY = 'clave'
qs = User.objects.all()
qss = qsstats.QuerySetStats(qs, 'date_joined')
hoy = datetime.date.today()
hace_2_semanas = hoy - datetime.timedelta(weeks=2)
users_stats = qss.time_series(hace_2_semanas, hoy)
return render_to_response('estadisticas.html', locals(), context_instance=RequestContext(request))
En user_stats tendremos una lista de tuplas con un elemento por cada día de las dos semanas.
En nuestra plantilla estadisticas.html cargaremos la API de javascript de Google. Crearemos una tabla de datos con DataTable y utilizaremos un gráfico tipo LineChart para su representación. La plantilla quedará de la siguiente manera:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Nuevos usuarios en las últimos 2 semanas</h1>
<div id="usuarios_14_dias"></div>
</body>
</html>
<script type="text/javascript" src="http://www.google.com/jsapi?key={{ GOOGLE_API_KEY }}"></script>
<script type="text/javascript"><!--
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(function() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Día');
data.addColumn('number', 'Usuarios nuevos');
data.addRows({{ users_stats|length }});
{% for s in users_stats %}
data.setValue({{ forloop.counter0 }}, 0, '{{ s.0|date:"d M" }}');
data.setValue({{ forloop.counter0 }}, 1, {{ s.1 }});
{% endfor %}
var chart = new google.visualization.LineChart(document.getElementById('usuarios_14_dias'));
chart.draw(data, {width: 620, height: 200, legend:'none'});
});
//--></script>
Obtendremos un gráfico como el siguiente:
Publicado por Antonio Melé el Domingo 15 d Agosto d 2010 | 3 comentarios | Categorías: plantillas, tutorial
Pisa es un conversor de HTML/XHTML a PDF escrito en Python. Vamos a ver cómo utilizar Pisa en nuestras vistas para convertir nuestras plantillas HTML a PDF.
Lo primero que tenemos que hacer es descargar e instalar Pisa. Pisa requiere ReportLab Toolkit, HTML5lib, pyPdf y PIL (útil: Cómo instalar PIL en Mac OSX). La forma más sencilla de instalar Pisa es mediante easy_install:
easy_install pisa
También podemos bajar el código fuente e instalarlo mediante el siguiente comando (en Linux y Mac Osx puedes necesitar incluir sudo delante):
python setup.py install
Una vez instalado Pisa añadiremos a views.py una función que nos permita convertir nuestras plantillas HTML a PDF. Utilizaremos una vista y una plantilla HTML que la función se encargará de convertir a formato PDF y devolverlo en la petición HTTP. La función recibirá la plantilla HTML renderizada previamente en nuestra vista mediante render_to_string.
Vamos a ver cómo quedaría nuestro views.py para una vista que reciba el id de un hipotético modelo Libro y devuelva un PDF con la información del mismo:
# -*- coding: utf-8 -*-
import ho.pisa as pisa
import cStringIO as StringIO
import cgi
from django.template import RequestContext
from django.template.loader import render_to_string
from django.http import HttpResponse
def generar_pdf(html):
# Función para generar el archivo PDF y devolverlo mediante HttpResponse
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), mimetype='application/pdf')
return HttpResponse('Error al generar el PDF: %s' % cgi.escape(html))
def libro_pdf(request, id):
# vista de ejemplo con un hipotético modelo Libro
libro=get_object_or_404(Libro, id=id)
html = render_to_string('libro_pdf.html', {'pagesize':'A4', 'libro':libro}, context_instance=RequestContext(request))
return generar_pdf(html)
Ahora sólo nos falta crear la plantilla libro_pdf.html para mostrar la información del libro:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>{{ libro.titulo }}</h1>
<p>{{ libro.descripcion }}</p>
</body>
</html>
Si queremos incluir imágenes en nuestro PDF deberemos utilizar su ruta local en la plantilla en vez de su URL. Imaginando que nuestro modelo Libro tuviera un campo imagen de tipo ImageField podríamos hacerlo de la siguiente forma:
<img src="{{ libro.imagen.path }}" />
Las imágenes suelen quedar más grandes de lo normal debido al mapeo de píxeles a puntos que hace Pisa. Para que las imágenes salgan con un tamaño adecuado conviene incluirles el estilo CSS zoom:
<img src="{{ libro.imagen.path }}" style="zoom: 80%;" />
Hay varias etiquetas especiales que aporta Pisa y que podemos utilizar en nuestras plantillas. Las más útiles son: pdf:pagenumber y pdf:nextpage. La primera nos permite incluir número de página en cada una de las páginas del documento PDF y la segunda nos permite definir dónde comienza otra página. Su uso en las plantillas HTML es muy sencillo:
<pdf:pagenumber>
<pdf:nextpage>
Como véis, las posibilidades son múltiples a la hora de generar PDFs dinámicamente con Python. Aquí tenéis un ejemplo de PDF que se genera dinámicamente mediante este método: Receta de dátiles con bacon
Publicado por Antonio Melé el Miércoles 4 d Agosto d 2010 | 5 comentarios | Categorías: plantillas, snippets, tutorial
oEmbed es un formato que permite usar una representación embebida de una URL en sitios web de terceros. La API de oEmbed permite a un sitio web incrustar contenido (como fotos o vídeos) de otros servicios web simplemente con un enlace al recurso que quiere se publicar. De esta forma se evita tener que utilizar una API distinta para incrustar contenidos de cada servicio web. Varios sitios como Flickr, Viddler, Qik, Hulu o Vimeo permiten acceder a sus contenidos mediante oEmbed. Además el sitio web oohEmbed sirve como wrapper para acceder a contenidos de otros sitios como YouTube, Wikipedia ó Wordpress.com entre otros.
Por ejemplo, la URL http://www.flickr.com/services/oembed?url=http://www.flickr.com/photos/ccgd/107274692/ devuelve el XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<oembed>
<version>1.0</version>
<type>photo</type>
<title>Trees Snow and Shadows</title>
<author_name>ccgd</author_name>
<author_url>http://www.flickr.com/photos/ccgd/</author_url>
<cache_age>3600</cache_age>
<provider_name>Flickr</provider_name>
<provider_url>http://www.flickr.com/</provider_url>
<width>500</width>
<height>363</height>
<url>http://farm1.static.flickr.com/44/107274692_c6c32bba58.jpg</url>
</oembed>
Si preferimos recibirlo en formato JSON basta con añadir el parámetro format=json a la misma URL.
Django-oembed es una aplicación que facilita transformar los enlaces a estos servicios que aparecen en el texto introducido por nuestros usuarios en el contenido embebido al que enlazan (vídeos, imágenes, etc.). De esta forma cuando un usuario enlaza a una imagen de Flickr ó un vídeo de Viddler podemos incluirlos directamente.
Para utilizar django-oembed basta con seguir los siguientes pasos:
Descargamos django-oembed e incluimos 'oembed' en el setting INSTALLED_APPS de nuestro settings.py
En la plantilla que queramos utilizar django-oembed para incrustar los contenidos enlazados cargamos los tags de oEmbed:
{% load oembed_tags %}
Utilizamos el tag oembed para reemplazar las URLs con enlaces de sitios que soportan oEmbed por los contenidos a los que éstos apuntan:
{% oembed %}
Una foto muy buena: http://www.flickr.com/photos/ccgd/107274692/
{% endoembed %}
Opcional: Algunos recursos soportan definir un ancho y alto concreto para el contenido a incrustar. Basta con definirlo en el tag oEmbed de la siguiente manera:
{% oembed 320x240 %} ...URL con contenido... {% endoembed %}
Publicado por Antonio Melé el Martes 21 d Julio d 2009 | 7 comentarios | Categorías: aplicaciones, plantillas, pluggables, templatetags
Suscríbete a nuestro feed RSS y al feed de la comunidad para estar al tanto de todo lo que ocurre entorno a Django.
Tú también puedes escribir en éste blog. Para hacerlo basta con que nos digas sobre qué quieres escribir un artículo relacionado con Django.
Utilizar un formulario para modificar 2 modelos
Descubriendo objetos similares por sus etiquetas