Como hemos mencionado, el sistema de plantillas se distribuye con etiquetas y filtros incorporados. Las secciones que siguen proveen un resumen de la mayoría de las etiquetas y filtros.
4.3.1. Etiquetas
4.3.1.1. Las etiquetas if
/ else
La etiqueta {% if %}
evalúa una variable, y si esta es "true" (esto es,
existe, no está vacía y no es un valor booleano falso), el sistema mostrará
todo lo que hay entre {% if %}
y {% endif %}
, por ejemplo:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
La etiqueta {% else %}
es opcional:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% else %}
<p>Get back to work.</p>
{% endif %}
Nota En Python, la lista vacía ([]
), la tupla vacía (()
), el diccionario
vacío ({}
), la cadena vacía (''
), el cero (0
), y el objeto especial
None
son False
en un contexto booleano. Todo lo demás es True
.
La etiqueta {% if %}
acepta and
, or
, o not
para testear
múltiples variables, o para negarlas. Por ejemplo:
{% if athlete_list and coach_list %}
Both athletes and coaches are available.
{% endif %}
{% if not athlete_list %}
There are no athletes.
{% endif %}
{% if athlete_list or coach_list %}
There are some athletes or some coaches.
{% endif %}
{% if not athlete_list or coach_list %}
There are no athletes or there are some coaches. (OK, so
writing English translations of Boolean logic sounds
stupid; it's not our fault.)
{% endif %}
{% if athlete_list and not coach_list %}
There are some athletes and absolutely no coaches.
{% endif %}
Las etiquetas {% if %}
no permiten las cláusulas and
y or
en la
misma etiqueta, porque el orden de evaluación lógico puede ser ambiguo. Por
ejemplo, esto es inválido:
{% if athlete_list and coach_list or cheerleader_list %}
No se admite el uso de paréntesis para controlar el orden de las operaciones.
Si necesitas paréntesis, considera efectuar la lógica en el código de la
vista para simplificar las plantillas. Aún así, si necesitas combinar
and
y or
para hacer lógica avanzada, usa etiquetas
{% if %}
anidadas, por ejemplo:
{% if athlete_list %}
{% if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{% endif %}
{% endif %}
Usar varias veces el mismo operador lógico están bien, pero no puedes combinar diferentes operadores. Por ejemplo, esto es válido:
{% if athlete_list or coach_list or parent_list or teacher_list %}
Ahí no hay una etiqueta {% elif %}
. Usa etiquetas {% if %}
anidadas
para conseguir alguna cosa:
{% if athlete_list %}
<p>Here are the athletes: {{ athlete_list }}.</p>
{% else %}
<p>No athletes are available.</p>
{% if coach_list %}
<p>Here are the coaches: {{ coach_list }}.</p>
{% endif %}
{% endif %}
Asegúrate de cerrar cada {% if %}
con un {% endif %}
. En otro caso,
Django levantará la excepción TemplateSyntaxError
.
4.3.1.2. La etiqueta for
La etiqueta {% for %}
permite iterar sobre cada uno de los elementos de una
secuencia. Como en la sentencia for
de Python, la sintaxis es for X in
Y
, dónde Y
es la secuencia sobre la que se hace el bucle y X
es el
nombre de la variable que se usará para cada uno de los ciclos del bucle. Cada
vez que atravesamos el bucle, el sistema de plantillas renderizará todo entre
{% for %}
y {% endfor %}
.
Por ejemplo, puedes usar lo siguiente para mostrar una lista de atletas tomadas
de la variable athlete_list
:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
Agrega reversed
a la etiqueta para iterar sobre la lista en orden inverso:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
Es posible anidar etiquetas {% for %}
:
{% for country in countries %}
<h1>{{ country.name }}</h1>
<ul>
{% for city in country.city_list %}
<li>{{ city }}</li>
{% endfor %}
</ul>
{% endfor %}
No se admite la "ruptura" de un bucle antes de que termine. Si quieres
conseguir esto, cambia la variable sobre la que estás iterando para que
incluya sólo los valores sobre los cuales quieres iterar. De manera similar,
no se soporta la sentencia continue
que se encarga de retornar
inmediatamente al inicio del bucle. (Lee la sección Filosofía y limitaciones
al final de este capítulo para comprender el razonamiento detrás de este
decisión de diseño.)
La etiqueta {% for %}
asigna la variable forloop
mágica a la plantilla
con el bucle. Esta variable tiene algunos atributos que toman información
acerca del progreso del bucle:
forloop.counter
es siempre asignada a un número entero representando el número de veces que se ha entrado en el bucle. Esta es indexada a partir de 1, por lo que la primera vez que se ingresa al bucle,forloop.counter
será1
. Aquí un ejemplo:
{% for item in todo_list %}
<p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}
forloop.counter0
es comoforloop.counter
, excepto que esta es indexada a partir de cero. Contendrá el valor0
la primera vez que se atraviese el bucle.forloop.revcounter
es siempre asignada a un entero que representa el número de iteraciones que faltan para terminar el bucle. La primera vez que se ejecuta el bucleforloop.revcounter
será igual al número de elementos que hay en la secuencia. La última vez que se atraviese el bucle, aforloop.revcounter
se la asignará el valor1
.forloop.revcounter0
es comoforloop.revcounter
, a excepción de que está indexada a partir de cero. La primera vez que se atraviesa el bucle,forloop.revcounter0
es asignada al número de elementos que hay en la secuencia menos 1. La última vez que se atraviese el bucle, el valor de esta será0
.forloop.first
es un valor booleano asignado aTrue
si es la primera vez que se pasa por el bucle. Esto es conveniente para ocasiones especiales:
{% for object in objects %}
{% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
{{ object }}
</li>
{% endfor %}
forloop.last
es un valor booleano asignado aTrue
si es la última pasada por el bucle. Un uso común es para esto es poner un carácter pipe entre una lista de enlaces:
{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}
El código de la plantilla de arriba puede mostrar algo parecido a esto: Link1 | Link2 | Link3 | Link4
forloop.parentloop
esta es una referencia al objeto padre deforloop
, en el caso de bucles anidados. Aquí un ejemplo::
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}</td>
<td>City #{{ forloop.counter }}</td>
<td>{{ city }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
La variable mágica forloop
está sólo disponible dentro de bucles. Después de
que el analizados sintáctico encuentra {% endfor %}
, forloop
desaparece.
Nota Dentro de un bloque {% for %}
, las variables existentes se
mueven fuera de tal manera de evitar sobreescribir la variable mágica
forloop
. Django expone ese contexto movido en forloop.parentloop
.
Generalmente no necesitas preocuparte por esto, si provees una variable a
la plantilla llamada forloop
(a pesar de que no lo recomendamos), se
llamará forloop.parentloop
mientras esté dentro del bloque
{% for %}
.
4.3.1.3. Las etiquetas ifequal
/ ifnotequal
El sistema de plantillas de Django a propósito no es un lenguaje de programación completo y por lo tanto no permite ejecutar sentencias arbitrarias de Python. (Más sobre esta idea en la sección Filosofía y limitaciones al final de este capítulo).
Sin embargo, es bastante común que una plantilla requiera
comparar dos valores y mostrar algo si ellos son iguales — Django provee la
etiqueta {% ifequal %}
para este propósito.
La etiqueta {% ifequal %}
compara dos valores y muestra todo lo que se
encuentra entre {% ifequal %}
y {% endifequal %}
si el valor es igual.
Este ejemplo compara las variables user
y currentuser
de la plantilla:
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}
Los argumentos pueden ser cadenas de texto encerradas con comillas simples o dobles. Ejemplo:
{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% endifequal %}
{% ifequal section "community" %}
<h1>Community</h1>
{% endifequal %}
Como {% if %}
, la etiqueta {% ifequal %}
admite un opcional {% else %}
:
{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% else %}
<h1>No News Here</h1>
{% endifequal %}
Sólo las variables de la plantilla, cadenas, enteros y números decimales son
permitidos como argumentos para {% ifequal %}
. Estos son ejemplos válidos:
{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'foo' %}
{% ifequal variable "foo" %}
Cualquier otro tipo de variables, tales como diccionarios de Python, listas, o
booleanos, no pueden ser comparados en {% ifequal %}
. Estos ejemplos son
inválidos:
{% ifequal variable True %}
{% ifequal variable [1, 2, 3] %}
{% ifequal variable {'key': 'value'} %}
Si necesitas comprobar cuando algo es verdadero o falso, usa la etiqueta
{% if %}
en vez de {% ifequal %}
.
4.3.1.4. Comentarios
Al igual que en HTML o en un lenguaje de programación como Python, el lenguaje
de plantillas de Django permite comentarios. Para designar un comentario, usa
{# #}
:
{# Esto es un comentario #}
Este comentario no será mostrado cuando la plantilla sea renderizada.
Un comentario no puede abarcar múltiples líneas. Esta limitación mejora el rendimiento del analizador sintáctico de plantillas. En la siguiente plantilla, la salida del renderizado mostraría exactamente lo mismo que la plantilla (esto es, la etiqueta comentario no será tomada como comentario):
This is a {# this is not
a comment #}
test.
4.3.2. Filtros
Como explicamos anteriormente en este capítulo, los filtros de plantillas son formas simples de alterar el valor de una variable antes de mostrarla. Los filtros se parecen a esto:
{{ name|lower }}
Esto muestra el valor de {{ name }}
después de aplicarle el filtro
lower
, el cual convierte el texto a minúscula. Usa un pipe (|
) para
aplicar el filtro.
Los filtros pueden estar en cadena — eso es, la salida del uno de los filtros
puede ser aplicada al próximo. Aquí un modismo común para escapar contenido del
texto, y entonces convertir los saltos de líneas en etiquetas <p>
:
{{ my_text|escape|linebreaks }}
Algunos filtros toman argumentos. Un filtro con argumento se ve de este modo:
{{ bio|truncatewords:"30" }}
Esto muestra las primeras 30 palabras de la variable bio
. Los argumentos de
los filtros están siempre entre comillas dobles.
Los siguientes son algunos de los filtros más importantes; el Apéndice F cubre el resto.
addslashes
: Agrega una con contra-barra antes de cualquier contra-barra, comilla simple o comilla doble. Esto es útil si el texto producido está incluido en un string de JavaScript.date
: Formatea un objetodate
odatetime
de acuerdo al formato tomado como parámetro (el formato de los strings está definido en el Apéndice F). Ejemplo:
{{ pub_date|date:"F j, Y" }}
escape
: Escapa ampersands (&), comillas, y corchetes del string tomado. Esto es usado para desinfectar datos suministrados por el usuario y asegurar que los datos son válidos para XML y XHTML. Específicamente,escape
hace estas conversiones:
* Convierte `&` en `&` * Convierte `<` en `<` * Convierte `>` en `>` * Convierte `"` (comilla doble) en `"` * Convierte `'` (comilla simple) en `'`
length
: Retorna la longitud del valor. Puedes usar este con una lista o con un string, o con cualquier objeto Python que sepa como determinar su longitud (o sea cualquier objeto que tenga el método__len__()
).