Flask

Flask

Tutorial Flask: Sintaxis Jinja2

Aprende la sintaxis fundamental y estructuras de control en Jinja2 para crear plantillas dinámicas con Flask de forma eficiente y segura.

Aprende Flask y certifícate

Sintaxis básica Jinja2

Jinja2 es el motor de plantillas que Flask utiliza por defecto para generar contenido HTML dinámico. Su sintaxis permite combinar código Python con HTML de manera elegante, separando la lógica de presentación del controlador y facilitando el mantenimiento del código.

Delimitadores fundamentales

Jinja2 utiliza tres tipos de delimitadores principales que definen cómo se interpreta el contenido dentro de las plantillas:

  • {{ }} - Para mostrar variables y expresiones
  • {% %} - Para estructuras de control (condicionales, bucles)
  • {# #} - Para comentarios que no aparecen en el HTML final
<!DOCTYPE html>
<html>
<head>
    <title>{{ titulo_pagina }}</title>
</head>
<body>
    {# Este es un comentario que no se verá en el navegador #}
    <h1>{{ mensaje_bienvenida }}</h1>
    
    {% if usuario_logueado %}
        <p>Bienvenido de vuelta</p>
    {% endif %}
</body>
</html>

Mostrar variables

La interpolación de variables se realiza mediante las llaves dobles {{ }}. Jinja2 automáticamente escapa el contenido HTML para prevenir ataques XSS, convirtiendo caracteres especiales en entidades HTML seguras:

<!-- En el controlador: nombre = "Ana García" -->
<h2>Hola {{ nombre }}</h2>
<!-- Resultado: <h2>Hola Ana García</h2> -->

<!-- En el controlador: edad = 25 -->
<p>Tienes {{ edad }} años</p>
<!-- Resultado: <p>Tienes 25 años</p> -->

Para acceder a propiedades de objetos o elementos de diccionarios, utiliza la notación de punto:

<!-- En el controlador: usuario = {"nombre": "Carlos", "email": "carlos@email.com"} -->
<p>Usuario: {{ usuario.nombre }}</p>
<p>Email: {{ usuario.email }}</p>

<!-- También funciona con listas -->
<!-- En el controlador: colores = ["rojo", "verde", "azul"] -->
<p>Primer color: {{ colores[0] }}</p>

Filtros básicos

Los filtros modifican el contenido de las variables antes de mostrarlas. Se aplican usando el símbolo pipe | después de la variable:

<!-- Convertir a mayúsculas -->
<h3>{{ nombre | upper }}</h3>

<!-- Convertir a minúsculas -->
<p>{{ email | lower }}</p>

<!-- Capitalizar primera letra -->
<span>{{ ciudad | capitalize }}</span>

<!-- Mostrar longitud -->
<small>Tu nombre tiene {{ nombre | length }} caracteres</small>

El filtro default es especialmente útil para manejar valores que pueden estar vacíos:

<!-- Si 'descripcion' está vacía, muestra el texto por defecto -->
<p>{{ descripcion | default("Sin descripción disponible") }}</p>

<!-- Versión abreviada -->
<p>{{ descripcion or "Sin descripción disponible" }}</p>

Expresiones y operadores

Jinja2 permite realizar operaciones matemáticas y comparaciones directamente en las plantillas:

<!-- Operaciones matemáticas -->
<p>Total: {{ precio * cantidad }}</p>
<p>Descuento: {{ precio * 0.1 }}</p>

<!-- Concatenación de strings -->
<h2>{{ nombre + " " + apellido }}</h2>

<!-- Comparaciones -->
<p>{{ edad >= 18 and "Mayor de edad" or "Menor de edad" }}</p>

Funciones integradas

Jinja2 incluye varias funciones útiles que puedes usar directamente en las plantillas:

<!-- Obtener longitud -->
<p>Hay {{ range(1, 6) | length }} elementos</p>

<!-- Generar rangos -->
{% for numero in range(1, 4) %}
    <span>{{ numero }}</span>
{% endfor %}

<!-- Función url_for para generar URLs -->
<a href="{{ url_for('inicio') }}">Ir al inicio</a>

Espacios en blanco y formato

Jinja2 respeta los espacios en blanco del HTML, pero puedes controlar el formato usando guiones en los delimitadores:

<!-- Sin control de espacios -->
<ul>
    {% for item in lista %}
    <li>{{ item }}</li>
    {% endfor %}
</ul>

<!-- Eliminando espacios extra -->
<ul>
    {%- for item in lista %}
    <li>{{ item }}</li>
    {%- endfor %}
</ul>

Escapado de contenido

Por defecto, Jinja2 escapa automáticamente el contenido HTML para seguridad. Si necesitas mostrar HTML sin escapar, usa el filtro safe:

<!-- Contenido escapado (seguro) -->
<p>{{ mensaje_usuario }}</p>

<!-- Contenido sin escapar (usar con precaución) -->
<div>{{ contenido_html | safe }}</div>

<!-- Alternativa usando autoescape -->
{% autoescape false %}
    <div>{{ contenido_html }}</div>
{% endautoescape %}

Esta sintaxis fundamental de Jinja2 te permite crear plantillas dinámicas que reciben datos desde tus controladores Flask y los presentan de manera estructurada en el navegador. La separación clara entre la lógica de presentación y los datos facilita el mantenimiento y la reutilización del código en aplicaciones web.

Variables y estructuras de control

Las estructuras de control en Jinja2 permiten crear plantillas dinámicas que adaptan su contenido según los datos recibidos desde el controlador. Estas estructuras utilizan la sintaxis {% %} y proporcionan la lógica necesaria para mostrar información de manera condicional o repetitiva.

Condicionales con if

La estructura if evalúa condiciones y muestra contenido según el resultado. Es fundamental para crear interfaces que se adapten al estado de la aplicación:

{% if usuario %}
    <div class="bienvenida">
        <h2>Hola {{ usuario.nombre }}</h2>
        <a href="{{ url_for('perfil') }}">Ver perfil</a>
    </div>
{% else %}
    <div class="login-prompt">
        <p>Por favor, inicia sesión</p>
        <a href="{{ url_for('login') }}">Acceder</a>
    </div>
{% endif %}

Las condiciones múltiples se manejan con elif, permitiendo evaluar varios escenarios:

{% if puntuacion >= 90 %}
    <span class="excelente">Excelente trabajo</span>
{% elif puntuacion >= 70 %}
    <span class="bueno">Buen trabajo</span>
{% elif puntuacion >= 50 %}
    <span class="regular">Puede mejorar</span>
{% else %}
    <span class="insuficiente">Necesita más práctica</span>
{% endif %}

Operadores lógicos en condicionales

Jinja2 soporta operadores lógicos que permiten crear condiciones más complejas:

{% if edad >= 18 and tiene_licencia %}
    <p>Puede conducir</p>
{% endif %}

{% if es_admin or es_moderador %}
    <button class="btn-admin">Panel de administración</button>
{% endif %}

{% if not usuario.bloqueado %}
    <form method="post">
        <button type="submit">Enviar comentario</button>
    </form>
{% endif %}

Verificación de existencia y contenido

Es común verificar si una variable existe o tiene contenido antes de mostrarla:

{% if productos %}
    <h3>Productos disponibles: {{ productos | length }}</h3>
{% else %}
    <p>No hay productos disponibles</p>
{% endif %}

{% if usuario.avatar %}
    <img src="{{ usuario.avatar }}" alt="Avatar">
{% else %}
    <div class="avatar-placeholder">Sin imagen</div>
{% endif %}

Bucles con for

El bucle for itera sobre listas, diccionarios y otros objetos iterables para generar contenido repetitivo:

<ul class="lista-productos">
{% for producto in productos %}
    <li>
        <h4>{{ producto.nombre }}</h4>
        <p>Precio: {{ producto.precio }}€</p>
        <span>Stock: {{ producto.stock }}</span>
    </li>
{% endfor %}
</ul>

Variables especiales en bucles

Jinja2 proporciona variables especiales dentro de los bucles que ofrecen información útil sobre la iteración actual:

<table>
{% for usuario in usuarios %}
    <tr class="{% if loop.index % 2 == 0 %}par{% else %}impar{% endif %}">
        <td>{{ loop.index }}</td>
        <td>{{ usuario.nombre }}</td>
        <td>{{ usuario.email }}</td>
        {% if loop.first %}
            <td><strong>Primer usuario</strong></td>
        {% elif loop.last %}
            <td><strong>Último usuario</strong></td>
        {% else %}
            <td>Usuario {{ loop.index }} de {{ loop.length }}</td>
        {% endif %}
    </tr>
{% endfor %}
</table>

Las variables de bucle más útiles incluyen:

  • loop.index - Número de iteración actual (empezando en 1)
  • loop.index0 - Número de iteración actual (empezando en 0)
  • loop.first - True si es la primera iteración
  • loop.last - True si es la última iteración
  • loop.length - Total de elementos en la iteración

Bucles con diccionarios

Los diccionarios se pueden iterar de diferentes maneras según la información que necesites mostrar:

<!-- Iterar solo valores -->
{% for valor in configuracion.values() %}
    <p>{{ valor }}</p>
{% endfor %}

<!-- Iterar claves y valores -->
{% for clave, valor in configuracion.items() %}
    <div class="config-item">
        <strong>{{ clave }}:</strong> {{ valor }}
    </div>
{% endfor %}

Bucles anidados

Los bucles anidados permiten trabajar con estructuras de datos más complejas:

{% for categoria in categorias %}
    <div class="categoria">
        <h3>{{ categoria.nombre }}</h3>
        <div class="productos">
        {% for producto in categoria.productos %}
            <div class="producto">
                <h4>{{ producto.nombre }}</h4>
                <p>{{ producto.descripcion }}</p>
            </div>
        {% endfor %}
        </div>
    </div>
{% endfor %}

Manejo de bucles vacíos

La cláusula else en bucles se ejecuta cuando la lista está vacía, evitando mostrar contenedores vacíos:

<div class="comentarios">
    <h3>Comentarios</h3>
    {% for comentario in comentarios %}
        <div class="comentario">
            <strong>{{ comentario.autor }}</strong>
            <p>{{ comentario.texto }}</p>
        </div>
    {% else %}
        <p class="sin-comentarios">Aún no hay comentarios</p>
    {% endfor %}
</div>

Filtrado en bucles

Puedes filtrar elementos durante la iteración usando condiciones dentro del bucle:

<h3>Productos en oferta</h3>
{% for producto in productos %}
    {% if producto.descuento > 0 %}
        <div class="oferta">
            <h4>{{ producto.nombre }}</h4>
            <span class="precio-original">{{ producto.precio }}€</span>
            <span class="precio-oferta">{{ producto.precio * (1 - producto.descuento) }}€</span>
        </div>
    {% endif %}
{% endfor %}

Asignación de variables

Jinja2 permite asignar variables dentro de las plantillas para reutilizar valores calculados:

{% set precio_total = producto.precio * cantidad %}
{% set descuento_aplicado = precio_total * 0.1 %}

<div class="resumen-compra">
    <p>Subtotal: {{ precio_total }}€</p>
    <p>Descuento: -{{ descuento_aplicado }}€</p>
    <p><strong>Total: {{ precio_total - descuento_aplicado }}€</strong></p>
</div>

Combinando estructuras de control

Las estructuras se pueden combinar para crear lógicas más sofisticadas:

{% for pedido in pedidos %}
    <div class="pedido">
        <h4>Pedido #{{ pedido.id }}</h4>
        
        {% if pedido.estado == 'pendiente' %}
            <span class="estado pendiente">Pendiente de pago</span>
        {% elif pedido.estado == 'procesando' %}
            <span class="estado procesando">En preparación</span>
        {% elif pedido.estado == 'enviado' %}
            <span class="estado enviado">Enviado</span>
        {% endif %}
        
        {% if pedido.productos %}
            <ul>
            {% for producto in pedido.productos %}
                <li>{{ producto.nombre }} x{{ producto.cantidad }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    </div>
{% else %}
    <p>No tienes pedidos realizados</p>
{% endfor %}

Estas estructuras de control proporcionan la flexibilidad necesaria para crear interfaces dinámicas que respondan a los datos enviados desde tus controladores Flask, manteniendo la separación entre la lógica de negocio y la presentación visual.

Aprende Flask online

Otras lecciones de Flask

Accede a todas las lecciones de Flask y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Flask y certifícate

Ejercicios de programación de Flask

Evalúa tus conocimientos de esta lección Sintaxis Jinja2 con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.