Etiquetas condicionales: if / else
La etiqueta {% if %} evalúa una variable. Si dicha variable resulta ser verdadera (es decir, existe, no está vacía y no es falsa), el contenido entre {% if %} y {% endif %} se renderiza:
{% if es_festivo %}
<p>¡Hoy es festivo!</p>
{% endif %}
La etiqueta {% else %} es opcional y permite definir un bloque alternativo:
{% if es_festivo %}
<p>¡Hoy es festivo!</p>
{% else %}
<p>Es un día laboral.</p>
{% endif %}
Valores considerados falsos en Python
En Python, los siguientes valores se evalúan como falsos: listas vacías ([]), tuplas vacías (()), diccionarios vacíos ({}), cadenas vacías (''), el número cero (0) y None. Cualquier otro valor se considera verdadero.
Operadores lógicos
La etiqueta {% if %} admite los operadores and, or y not para combinar múltiples condiciones:
{% if jugadores and entrenadores %}
Hay jugadores y entrenadores disponibles.
{% endif %}
{% if not jugadores %}
No hay jugadores registrados.
{% endif %}
{% if jugadores or entrenadores %}
Hay jugadores o entrenadores disponibles.
{% endif %}
{% if jugadores and not entrenadores %}
Hay jugadores pero ningún entrenador.
{% endif %}
Restricción importante: No se permite mezclar and y or dentro de una misma etiqueta {% if %}, ya que generaría ambigüedad lógica. Por ejemplo, esto provocaría un error:
{% if jugadores and entrenadores or arbitros %} {# INCORRECTO #}
Tampoco se soportan paréntesis para agrupar. La solución consiste en anidar etiquetas {% if %}:
{% if jugadores %}
{% if entrenadores or arbitros %}
Hay jugadores, y también entrenadores o árbitros.
{% endif %}
{% endif %}
Usar el mismo operador repetidamente sí está permitido:
{% if jugadores or entrenadores or padres or profesores %}
No existe {% elif %}. Para simularlo, se anidan etiquetas {% if %} dentro de {% else %}:
{% if jugadores %}
<p>Jugadores: {{ jugadores }}</p>
{% else %}
<p>No hay jugadores.</p>
{% if entrenadores %}
<p>Entrenadores: {{ entrenadores }}</p>
{% endif %}
{% endif %}
Cada {% if %} debe cerrarse obligatoriamente con {% endif %}. De lo contrario, Django lanzará un TemplateSyntaxError.
Iteración con for
La etiqueta {% for %} permite recorrer una secuencia. La sintaxis es for elemento in coleccion, donde coleccion es la secuencia a recorrer y elemento es la variable que representa cada item:
<ul>
{% for jugador in lista_jugadores %}
<li>{{ jugador.nombre }}</li>
{% endfor %}
</ul>
El modificador reversed invierte el orden de iteración:
{% for jugador in lista_jugadores reversed %}
...
{% endfor %}
Las etiquetas {% for %} pueden anidarse:
{% for pais in paises %}
<h1>{{ pais.nombre }}</h1>
<ul>
{% for ciudad in pais.ciudades %}
<li>{{ ciudad }}</li>
{% endfor %}
</ul>
{% endfor %}
Django no proporciona mecanismos para romper (break) o saltar (continue) iteraciones. Para lograr un comportamiento similar, se puede filtrar la colección antes de iterarla.
La variable forloop
Dentro de cada bucle {% for %}, se dispone de una variable especial llamada forloop con información sobre el progreso del ciclo:
- forloop.counter: contador iniciado en 1.
- forloop.counter0: contador iniciado en 0.
- forloop.revcounter: número de elementos restantes (comienza con el total y termina en 1).
- forloop.revcounter0: similar al anterior pero terminando en 0.
- forloop.first:
Trueen la primera iteración. - forloop.last:
Trueen la última iteración. - forloop.parentloop: referencia al
forloopdel bucle padre (en bucles anidados).
Ejemplo de uso de forloop.counter:
{% for tarea in lista_tareas %}
<p>{{ forloop.counter }}: {{ tarea }}</p>
{% endfor %}
Ejemplo con forloop.first:
{% for obj in objetos %}
{% if forloop.first %}<li class="primero">{% else %}<li>{% endif %}
{{ obj }}
</li>
{% endfor %}
Ejemplo con forloop.last para separar elementos con un pipe:
{% for enlace in enlaces %}{{ enlace }}{% if not forloop.last %} | {% endif %}{% endfor %}
Resultado: Enlace1 | Enlace2 | Enlace3
Ejemplo con forloop.parentloop en bucles anidados:
{% for pais in paises %}
<table>
{% for ciudad in pais.ciudades %}
<tr>
<td>País #{{ forloop.parentloop.counter }}</td>
<td>Ciudad #{{ forloop.counter }}</td>
<td>{{ ciudad }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
La variable forloop solo existe dentro del bucle. Una vez alcanzado {% endfor %}, deja de estar disponible. Si existe una variable de contexto llamada forloop, dentro del bucle se renombra y se puede acceder mediante forloop.parentloop.
Comparaciones con ifequal / ifnotequal
El sistema de plantillas de Django no permite ejecutar código Python directamente. Sin embargo, comparar valores es tan común que se ofrece la etiqueta {% ifequal %}:
{% ifequal usuario usuario_actual %}
<h1>¡Bienvenido!</h1>
{% endifequal %}
Se pueden comparar con cadenas literales (usando comillas simples o dobles):
{% ifequal seccion 'noticias' %}
<h1>Noticias del sitio</h1>
{% endifequal %}
{% ifequal seccion "comunidad" %}
<h1>Comunidad</h1>
{% endifequal %}
Admite {% else %}:
{% ifequal seccion 'noticias' %}
<h1>Noticias del sitio</h1>
{% else %}
<h1>Sin noticias</h1>
{% endifequal %}
Solo se permiten como argumentos: variables de plantilla, cadenas, enteros y decimales. Ejemplos válidos:
{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'texto' %}
{% ifequal variable "texto" %}
No se permiten booleanos, listas ni diccionarios:
{% ifequal variable True %} {# INCORRECTO #}
{% ifequal variable [1, 2, 3] %} {# INCORRECTO #}
{% ifequal variable {'k': 'v'} %} {# INCORRECTO #}
Para evaluar si una variable es verdadera o falsa, se debe usar {% if %}.
Comentarios
Los comentarios en plantillas se delimitan con {# #}:
{# Esto es un comentario #}
El contenido comentado no aparece en la salida renderizada. No se permiten comentarios multilínea con esta sintaxis, ya que está diseñada para maximizar el rendimiento del parser. Para comentarios de múltiples líneas se puede usar {% comment %} y {% endcomment %}.
Otras etiquetas releventes
block
Define una sección que las plantillas hijas pueden sobrescribir mediante herencia.
csrf_token
Inserta el campo oculto necesario para proteger formularios contra ataques CSRF.
extends
Indica que la plantilla actual hereda de otra. Acepta el nombre del template padre como cadena o variable.
include
Carga y renderiza otra plantilla usando el contexto actual. Se pueden pasar parámetros adicionales:
{% include "fragmento.html" with nombre="Ana" saludo="Hola" %}
Con only se restringe el contexto únicamente a los parámetros indicados:
{% include "fragmento.html" with saludo="Hola" only %}
url
Genera una URL basada en el nombre de una vista definida en la configuración de URLs.
load
Carga un conjunto de etiquetas o filtros personalizados desde una librería específica.
autoescape
Activa o desactiva el escape automático de HTML dentro de un bloque:
{% autoescape on %}
{{ contenido }}
{% endautoescape %}
cycle
Alterna entre valores en cada iteración. Acepta cadenas y variables mezcladas:
{% for item in coleccion %}
<tr class="{% cycle 'fila1' 'fila2' 'fila3' %}">
...
</tr>
{% endfor %}
Se puede asignar un alias con as para referenciar el valor actual fuera del ciclo:
{% cycle 'fila1' 'fila2' as fila_color %}
<td class="{{ fila_color }}">...</td>
El parámetro silent permite definir el ciclo sin imprimir inmediatamente:
{% cycle 'fila1' 'fila2' as fila_color silent %}
{% cycle fila_color %}
filter
Aplica uno o varios filtros al contenido del bloque:
{% filter force_escape|lower %}
Este texto será escapado y convertido a minúsculas.
{% endfilter %}
firstof
Devuelve el primer argumento que evalúe como verdadero:
{% firstof var1 var2 var3 "valor por defecto" %}
for ... empty
Define un bloque a mostrar cuando la colección está vacía:
<ul>
{% for jugador in lista_jugadores %}
<li>{{ jugador.nombre }}</li>
{% empty %}
<li>No hay jugadores en la lista.</li>
{% endfor %}
</ul>
ifchanged
Dentro de un bucle, detecta si un valor ha cambiado respecto a la iteración anterior:
{% for partido in partidos %}
<div style="background-color:
{% ifchanged partido.id_boleta %}
{% cycle "rojo" "azul" %}
{% else %}
gris
{% endifchanged %}
">{{ partido }}</div>
{% endfor %}
now
Muestra la fecha y hora actuales con un formato determinado:
Hoy es {% now "jS F Y H:i" %}
Se pueden usar formatos predefinidos como DATE_FORMAT, DATETIME_FORMAT, SHORT_DATE_FORMAT o SHORT_DATETIME_FORMAT.
spaceless
Elimina los espacios en blanco entre etiquetas HTML:
{% spaceless %}
<p>
<a href="foo/">Foo</a>
</p>
{% endspaceless %}
Resultado: <p><a href="foo/">Foo</a></p>
with
Asigna un alias a una expresión compleja para simplificar su uso dentro del bloque:
{% with total=empresa.empleados.cantidad %}
{{ total }} empleado{{ total|pluralize }}
{% endwith %}
También se pueden definir múltiples variibles:
{% with a=1 b=2 %}
...
{% endwith %}
debug
Imprime información de depuración, incluyendo el contexto actual y los módulos importados.