Jinja2 en Flask 3

Uno de los problemas que tenemos actualmente es que, no tenemos una forma efectiva de presentar los datos al usuario final, al ser Flask una tecnología web, lo usual es presentar estos datos en una página web; es aquí donde cobra importancia lo que se conoce como motor de plantillas; un motor de plantillas es un recurso utilizado para presentar estos datos desde el servidor y generar una página web en el proceso, son la siguiente capa del MVC que corresponde a la vista y permite separar la lógica de presentación de los datos; para ello, se emplean un conjunto de características para lograr manipular los datos del servidor y generar la página HTML que será consumida mediante el usuario, características como impresiones, filtros, condicionales, ciclos o importaciones, permite generar este código HTML necesario para representar una página web. Son muy empleados en la programación del lado del servidor, ya que permiten la presentación de datos sin tener que modificar el código fuente.

En pocas palabras, con un motor de plantillas es posible presentar los datos manejados por el servidor, específicamente en nuestro caso en Flask y generar el HTML en el proceso; por ejemplo, si tenemos una lista de usuarios, podemos imprimirlo en una tabla o similar en HTML usando ciertas funcionalidades (directivas).

A lo largo de esta guía te mostraré cómo usar Jinja2 en Flask 3, desde la configuración básica hasta la herencia de plantillas, pasando por condicionales, bucles y filtros, se da por hecho de que ya tienes tu app completamente funcional y eres capaz de definir las variables de entorno en Flask mediante los .env

Qué es un motor de plantillas y para qué sirve

Un motor de plantillas es una herramienta que conecta la lógica del servidor con la capa visual del navegador, generando HTML dinámico. En el contexto del patrón MVC, corresponde a la capa View. Gracias a este enfoque, puedes separar la presentación de los datos y mantener un código más fácil de mantener.

Sin un motor de plantillas era casi imposible mostrar datos de forma elegante; todo se reducía a concatenar cadenas HTML. Jinja2 vino a resolver eso.

Ventajas de usar Jinja2 en Flask 3

  • Sintaxis simple y parecida a Python.
  • Soporta variables, filtros, condicionales y bucles.
  • Permite reutilizar código con bloques y herencia.
  • Está integrado por defecto en Flask.

Sobre Jinja

Jinja es un motor de plantillas escrito en Python diseñado para ser simple y expresivo; Jinja es un motor plantillas que puede ser usado en otros frameworks como FastAPI, también es muy similar al empleado por Django.

Con Jinja como motor de plantilla podemos representar fácilmente las respuestas de la API.

El motor de plantillas de Jinja utiliza corchetes { } para distinguir sus expresiones y sintaxis del HTML:

  1. La sintaxis {{ }} se denomina bloque variable y la podemos usar para imprimir en la plantilla.
  2. La sintaxis {% %} alberga estructuras de control como if/else, bucles y macros.
  3. La sintaxis {#  #} son para comentarios.

Configurar Jinja en Flask

De forma predeterminada, Flask busca las plantillas/templates carpeta llamada templates en el nivel raíz de la aplicación. Si esta carpeta está presente, Flask leerá automáticamente el contenido haciendo que el contenido de esta carpeta esté disponible para su uso con el método render_template() desde los controladores; así que, crearemos la carpeta mencionada anteriormente:

app\my_app\templates

Estructura de carpetas y archivo templates

Flask busca por defecto las plantillas dentro de una carpeta llamada templates ubicada en el nivel raíz de la aplicación:

my_app/
├── __init__.py
└── templates/
    └── index.html

Comencemos creando una página HTML básica, que sería un template en Jinja:

my_app\templates\index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Page</title>
</head>

<body>
    <h1>Hello Flask</h1>
    <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Reiciendis libero possimus nihil ipsam quam deleniti
        voluptas eaque qui. Necessitatibus corporis quas odio tenetur quos, recusandae itaque doloremque assumenda
        consequatur aliquam.</p>
</body>

</html>

Desde un controlador, devolvemos el template en vez de un texto como lo teníamos anteriormente:

my_app\__init__.py

from flask import render_template, request 

@app.route('/') 
@app.route('/hello') 
def hello_world(): 
    return render_template('index.html') 

Pasar variables dinámicas desde Flask a Jinja2

Hagamos unos cambios puntuales para que podamos entender el potencial de Jinja en conjunto de frameworks del lado del servidor como Flask, que es pasar datos de manera dinámica desde Flask.

En una aplicación real, normalmente querrás enviar datos desde Flask hacia el HTML. En mi caso, suelo hacerlo para personalizar mensajes o listas dinámicas:

my_app\__init__.py

from flask import Flask, render_template, request
app = Flask(__name__)

@app.route('/hello')
def hello():
    name = request.args.get('name', 'DesarrolloLibre')
    return render_template('index.html', name=name)

Con:

request.args.get('name', 'DesarrolloLibre') 

Se obtiene un parámetro vía GET llamado "name"; el parámetro luego es suministrado a la plantilla mediante:

name=name

En donde:

name=name

Es la variable llamada name:

name=name

Indica la forma de acceso de la variable name en el controlador desde la vista:

name=name

Desde el template o vista, imprimimos referenciando la variable desde la vista con dobles llaves:

my_app\templates\index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Page</title>
</head>

<body>
    <h1>Hello {{name}}</h1>
</body>
</html>

Y veremos en la pantalla:

http://127.0.0.1:5000/

Hello DesarrolloLibre

Puedes personalizar el nombre, pasando un parámetro vía GET:

http://127.0.0.1:5000/?name=Andrew

Hello Andrew

En el caso de que quieras personalizar el nombre de la carpeta o ubicación de los templates, lo puedes definir al momento de crear la instancia principal de la aplicación:

app = Flask(__name__, template_folder="<ROUTETEMPLATES>")

Las distintas características que nos ofrece Jinja como la anterior, las veremos en detalle en el siguiente apartado.

Primeros pasos con Jinja2: Sintaxis básica

Impresiones con {{ }}

Todo lo que encierres dentro de {{ }} se imprime directamente en la plantilla.
Ejemplo:

<p>{{ mensaje }}</p>

En este apartado vamos a conocer las características principales de Jinja, que van desde el uso de bloques de control, hasta el uso de filtros y del template en general.

Estructuras de control {% if %}, {% for %} y comentarios {# #}

Uno de los elementos cruciales en los motores de plantillas son los bloques de control; podemos realizar desde condicionales hasta ciclos for que funcionan de la misma manera que en Python; con esto es posible realizar lógicas condicionales para renderizar bloques HTML si se cumple una condición al igual que iterar colecciones de datos completas, por ejemplo, un listado de tareas en una tabla o similares.

Condicionales

Podemos hacer uso de los condicionales para evaluar condiciones de verdadero y falso:

<div>
    {% if True %}
        Is TRUE
    {% endif %}
</div>

Los condicionales en Jinja, son exactamente iguales que en Python, podemos usar el else, or, and, etc:

<div>
    {% if True and False %}
        Is True
    {% else %}
        Not is True
    {% endif %}
</div>

Ciclo for

Al igual que ocurre con el ciclo for en Python, podemos usarlo en Jinja:

<ul>
{% for item in items %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

Dentro de un bloque de bucle for, puede acceder a algunas variables especiales, entre las principales tenemos:

  • loop.index: Obtiene el índice actual de la iteración comenzando desde uno.
  • loop.index0: Obtiene el índice actual de la iteración comenzando desde cero.
  • loop.first: True si es la primera iteración.
  • loop.last: True si es la última iteración.
  • loop.length: Retorna el tamaño de la lista.

Por ejemplo, para usar la variable de last:

<ul>
    {% for e in [1,2,3,4,5,6,10] %}
    <li>{{ e }} {{ loop.last }} </li>
    {% endfor %}
</ul>

Todas las variables deben de ser empleadas dentro del ciclo for.

Filtros en Jinja2

Los filtros en Jinja son una de las características más importantes y versátiles que existen en este motor de plantillas; permiten manipular el contenido que se muestra en una plantilla. Hay varios filtros predefinidos en Jinja aunque podemos extender los existentes con filtros personalizados; los filtros se aplican a las variables que separa por ejemplo contar la longitud de una cadena de texto, unir textos en uno solo, separar por algún separador, dar formatos a fechas números y un largo etc; en resumen, permiten realizar manipulaciones personalizadas del contenido.

Para emplear un filtro, se usa el operador de pipe (|) luego de especificar el argumento o argumentos, y luego del operador de pipe, el filtro que quieras emplear:

<DATA> | <FILTER>

Veamos algunos filtros en Jinja.

Filtro default

El filtro default se usa para reemplazar la salida si la variable tiene un valor nulo (no se encuentra definida):

{{ task | default('This is a default Task') }}

Por ejemplo, si task es nula, tendremos una salida como:

This is a default Task

Si task estuviera definida o evaluamos, por ejemplo, un número.

{{ 5 | default('This is a default Task') }}

Veríamos el número por pantalla:

5

Filtro escape

Reemplace los caracteres &, <, >, ' y " en el string suministrado con caracteres seguros para mostrar el texto que contenga los caracteres HTML:

{{ "<title>Todo Application</title>" | escape }}

Tendremos como salida:

&lt;title1&gt;Todo Application&lt;/title1&gt;

Filtro conversion

Estos filtros incluyen filtros int y float utilizados para convertir de un tipo de datos a otro:

{{ 3.142 | int }}

Tendremos como salida:

3

O por ejemplo:

{{ 31 | float }}

Tendremos como salida:

31.0

Filtro max

Devuelve el elemento más grande en la lista:

{{ [1, 2, 3, 4, 5]|max }}

Y tendremos:

5

Filtro min

Devuelve el elemento más pequeño en la lista:

{{ [1, 2, 3, 4, 5]|min }}

Y tendremos:

1

Herencia y bloques en plantillas

Qué es una plantilla base (master.html)

Una de las mejores características de Jinja2 es la herencia de plantillas, que permite reutilizar una estructura HTML común en varias vistas.

Por ejemplo:

<!-- master.html -->
<!DOCTYPE html>
<html lang="es">
<head>
 <title>{% block title %}{% endblock %}</title>
</head>
<body>
 <header>{% block header %}{% endblock %}</header>
 <main>{% block content %}{% endblock %}</main>
</body>
</html>

Muchas de las funcionalidades que podemos usar en Jinja residen en bloques de código. Estos lucen como:

{% <BLOCKTYPE> %} 
<BODY>
{% <ENDBLOCKTYPE> %}

Los bloques de código permiten tanto una mejor ordenación para el código como dividir el bloque en secciones usando diversos tipos de bloques que permiten realizar una determinada función.

Herencia de templates

En este apartado, veremos cómo usar los templates en Jinja; específicamente como poder usar templates maestros para poder reutilizar un esqueleto base en múltiples vistas y cómo incluir fragmentos de vistas (otras plantillas) en plantillas.

En este apartado usaremos el término vista, template y plantilla de manera equivalente.

Template maestro

Muchas veces es necesario tener una vista maestra en donde se actualice cierto contenido clave; por ejemplo, si tenemos un módulo de gestión, los elementos comunes entre pantalla pudieran ser una cabecera para definir los enlaces, así como logo, el footer y un contenedor, los elementos dinámicos se presentaron en el medio de la pantalla.

En Jinja podemos usar templates maestros para implementar este tipo de lógicas; a la final, una vista maestra no es más que un template, en donde tenemos bloques o apartados especiales (block) para indicar en donde va el contenido que va a variar y este template maestro es incluido en los templates finales y mediante los bloques especificado en el template maestro, se referencian en los templates finales con el contenido final; esta funcionalidad de Jinja se conoce como herencia de plantillas.

Creemos una plantilla base o esqueleto que es la que va a ser usada para ser heredada desde otras plantillas:

master.html

<!DOCTYPE html>
<html lang="es">
<head>
    {% block head %}
        <link rel="stylesheet" href="style.css" />
        <title>{% block title %}{% endblock %} - DesarrolloLibre</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
           DL by <a href="#">Contact</a>.
        {% endblock %}
    </div>
</body>
</html>

En el código anterior, se definen 3 bloques:

  1. Uno para el título en el header.
  2. Uno para el título en el contenido.
  3. Otro para el contenido, que serían el lugar donde colocamos el listado, formulario entre otros.

Cómo extender y sobrescribir bloques

<!-- home.html -->
{% extends "master.html" %}
{% block title %}Inicio{% endblock %}
{% block content %}
 <h2>Bienvenido a mi sitio</h2>
{% endblock %}

Reutilización de vistas con herencia de plantillas

Con este patrón, puedes cambiar un solo bloque en master.html y automáticamente actualizar toda tu aplicación. Es una de las razones por las que considero que Jinja2 simplifica la vida de los desarrolladores Flask.

Conclusión

Dominar Jinja2 en Flask 3 no solo te permitirá crear interfaces limpias y dinámicas, sino que además te ayudará a mantener tu aplicación organizada bajo buenas prácticas del patrón MVC. En mi experiencia, entender cómo pasar variables, aplicar filtros y usar herencia de plantillas fue un antes y un después en mi forma de desarrollar con Flask.

El siguiente paso natural sería integrar estas plantillas con bases de datos y APIs, generando vistas dinámicas con datos reales.

Preguntas frecuentes (FAQs)

¿Qué es Jinja2 en Flask?
Es el motor de plantillas que genera HTML dinámico a partir de variables y lógica definida en Flask.

¿Dónde guarda Flask las plantillas Jinja2?
En la carpeta templates/ del proyecto.

¿Qué diferencia hay entre Jinja2 y Django Templates?
Son similares en sintaxis, pero Jinja2 es independiente y más flexible, ideal para Flask.

¿Cómo pasar datos de Flask a Jinja2?
Usando render_template() y pasando variables como argumentos.

¿Qué son los filtros en Jinja2?
Funciones que transforman el contenido antes de mostrarse (por ejemplo, |default, |escape, |upper).

El siguiente paso, es mostrar otros tipos de datos mediante el uso de los mensajes Flash en Flask.

Acepto recibir anuncios de interes sobre este Blog.

Daremos una introducción a Jinja2 enfocado a Flask, conoceremos sobre el motor de plantillas, los filtros, herencia de templates, bloques entre otros aspectos.

| 👤 Andrés Cruz

🇺🇸 In english