Guía completa de etiquetas de plantilla en Django

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: True en la primera iteración.
  • forloop.last: True en la última iteración.
  • forloop.parentloop: referencia al forloop del 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.

Etiquetas: Django templates template tags Django DTL template inheritance

Publicado el 10-8 04:50