Alternativa al sistema de templates de Django, parte 1: Jinja2
Django es un gran framework web pero tiene un sistema de templates que a un programador puede resultarle un tanto limitado:
- No es posible asignar variables ni cambiar sus valores.
- No hay distinción entre métodos y propiedades.
- No es posible pasar parámetros a los métodos.
- No existe la sentencia elif ! :P
Hay varias alternativas entre las que elegir: Jinja2, Mako, Genshi, Cheetah. De todas, Jinja2 es el que tiene la sintáxis más compatible con Django, pero tiene otra filosofía y por lo tanto permite hacer más cosas. Empecemos entonces por la instalación.
Instalación de Jinja2
Jinja puede instalarse medianteeasy_install:
Y medianteapten debian y derivados:
Integración con Django
El diseño de bajo acoplamiento de Django permite que usar otro sistema de templates sea sencillo. Para Jinja basta con definir una variable de ambiente y escribir los métodos alternativos pararender_to_stringyrender_to_response. A continuación muestro la forma más simple que encontré. Hay otras más sofisticadas por ahí (esta y esta) pero básicamente hacen lo mismo:
from django.conf import settings
from django.http import HttpResponse
from jinja2 import Environment, FileSystemLoader
jinja_env = Environment(
loader=FileSystemLoader(getattr(settings, 'TEMPLATE_DIRS')))
def render_to_string(template_path, context=None, **kwargs):
template = jinja_env.get_template(template_path)
context = dict(context or {})
return template.render(**context)
def render_to_response(template_path, context=None, **kwargs):
return HttpResponse(render_to_string(template_path, context, **kwargs),
mimetype=None)
La vista entonces no difiere mucho de una vista tradicional:
from jinja_helper import render_to_response
def index(request):
title = "hello world."
return render_to_response('index.html', locals())
Escribir un libro filtro
Un filtro es una función de python que se agrega a la listafilters:
from jinja_helper import jinja_env
def toupper(s):
return s.upper()
jinja_env.filters['toupper'] = toupper
Cuando el filtro recibe un sólo argumento la forma de uso es similar a Django:
Para pasar más argumentos se usa la formaarg1|func(arg2, ...).
Para la asignación a jinja_env.filter pordemos usar un decorador:
from jinja_helper import register_filter
@register_filter()
def toupper(s):
return s.upper()
def register_filter(name=None):
def dec(func):
if name:
func.__name__ = name
jinja_env.filters[func.__name__] = func
return func
return dec
Tags? no, funciones
Para emular un tag de inclusión de django hay que definir una función que retorne un render_to_string y agregarla a la listaglobals:
from jinja_helper import jinja_env, render_to_string
def menu():
items = ('about', 'contact')
return render_to_string('menu.html', dict(items=items))
jinja_env.globals['menu'] = menu
El template podría ser algo así:
{{ menu() }}
De nuevo, podríamos agregar un poco de azúcar a la sintáxis:
from jinja_helper import register_block
@register_block('menu.html')
def menu():
items = ('about', 'contact')
return dict(items=items)
def register_block(template_path, name=None):
def dec(func):
def func2(*args, **kwargs):
return render_to_string(template_path, func(*args, **kwargs))
func2.__name__ = name if name else func.__name__
jinja_env.globals[func2.__name__] = func2
return func2
return dec
Descarga
El ejemplo completo puede descargarse desde aquí: mysite-jinja2.tar





