Guía Completa de Jinja2 para Desarrollo de Plantillas en Python

  Introducción a Jinja2

Jinja2 es un motor de plantillas para Python que permite generar HTML de forma dinámica. Es ampliamente utilizado en frameworks web como Flask, Django y FastAPI para separar la lógica del backend de la presentación en el frontend. Con Jinja2, puedes trabajar con variables, estructuras de control (como condicionales y bucles), heredar y reutilizar plantillas, y usar filtros y macros para personalizar y optimizar la creación de tus interfaces. Esto hace que el código sea más limpio, modular y fácil de mantener.

¿Qué es Jinja2?

Como se dijo anteriormente, Jinja2 es un motor de plantillas moderno y amigable para Python. Es rápido, ampliamente utilizado y seguro con soporte completo de unicode.

  Características principales de Jinja2

  • Herencia de plantillas
  • Ejecución anticipada
  • Configuración altamente personalizable
  • Sintaxis automática de escape HTML
  • Sistema de filtros incorporado

Variables en Jinja2

En Jinja2, las variables se muestran utilizando la sintaxis de doble llave {{ }}, lo que permite insertar valores dinámicos en la plantilla de manera sencilla.

bash
{# Definición básica de variables #}
{{ nombre }}
{{ usuario.nombre }}
{{ diccionario['clave'] }}

Mostrar Variables en Jinja2

Para mostrar variables en Jinja2, se usa la sintaxis {{ nombre-variable }}, que inserta el valor de la variable directamente en la plantilla. Esta sintaxis también permite aplicar filtros para modificar el valor antes de mostrarlo.

bash
{# Operaciones básicas #}
{{ nombre | capitalize }}  {# Capitaliza la primera letra del nombre #}
{{ precio * 1.21 }}  {# Calcula el precio con IVA (21%) #}
{{ lista[0] }}  {# Accede al primer elemento de la lista #}

{# Acceso a atributos #}
{{ usuario.nombre }}  {# Muestra el nombre del usuario accediendo al atributo directamente #}
{{ usuario['email'] }}  {# Muestra el correo electrónico del usuario usando notación de diccionario #}

{# Uso con filtros #}
{{ nombre | default('Anónimo') }}  {# Muestra 'Anónimo' si la variable nombre está vacía o no definida #}
{{ texto | truncate(100) }}  {# Corta el texto a 100 caracteres, agregando '...' si es más largo #}

Comentarios en Jinja2

Existen tres tipos de comentarios:

bash
{# Este es un comentario que no aparecerá en el output #}

{##
Este es un comentario
multilínea en Jinja2
#}

{# TODO: Revisar esta sección #}

Estructuras de Control en Jinja2


Condicional if

Este ejemplo verifica si la variable usuario está definida. Si es así, muestra un mensaje de bienvenida utilizando el nombre del usuario.

bash
{% if usuario %}
  <p>Bienvenido, {{ usuario.nombre }}!</p>
{% endif %}

Condicional elif

Aquí se evalúa la variable temperatura. Si es mayor que 30, se muestra un mensaje sobre el calor. Si no, pero es mayor que 20, se muestra un mensaje sobre el clima agradable.

bash
{% if temperatura > 30 %}
  <p>Hace calor, ¡sal de la playa!</p>
{% elif temperatura > 20 %}
  <p>El clima es agradable, perfecto para un paseo.</p>
{% endif %}

Condicional else

Este ejemplo evalúa la variable hora. Si es menor que 12, muestra un saludo de buenos días; de lo contrario, muestra un saludo de buenas tardes.

bash
{% if hora < 12 %}
  <p>¡Buenos días!</p>
{% else %}
  <p>¡Buenas tardes!</p>
{% endif %}

Condicionales (if, elif, else)

Esta estructura evalúa la variable edad. Dependiendo de su valor, muestra un mensaje diferente. Utiliza if, elif y else para manejar múltiples condiciones.

bash
edad = 21

{% if edad >= 18 %}
  <p>Eres mayor de edad.</p>
{% elif edad >= 13 %}
  <p>Eres un adolescente.</p>
{% else %}
  <p>Eres un niño.</p>
{% endif %}

# Salida: Eres mayor de edad.

Bucles en Jinja2


Bucles (for)

Este bucle recorre cada elemento en lista y genera un <li> para cada uno. Es útil para mostrar listas de elementos dinámicamente.

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

Estructuras de control con loop

Utiliza el objeto loop para acceder a información del bucle, como loop.index, que proporciona el índice actual del elemento dentro del bucle (comenzando desde 1).

bash
<ul>
  {% for item in lista %}
      <li>{{ loop.index }}: {{ item }}</li> {# Muestra el índice del elemento #}
  {% endfor %}
</ul>
  Atributos de Loop

  • loop.index: Índice actual (empezando desde 1)
  • loop.index0: Índice actual (empezando desde 0)
  • loop.revindex: Número de iteraciones restantes
  • loop.first: True si es la primera iteración
  • loop.last: True si es la última iteración
  • loop.length: Número total de items

Condicionales anidados

Se usa un condicional anidado para comprobar si un usuario está definido y, en caso afirmativo, si es administrador o no. Esto permite manejar casos más complejos de forma organizada.

bash
{% if usuario %}
  <p>Hola, {{ usuario.nombre }}!</p>
  {% if usuario.admin %}
      <p>Tienes acceso completo.</p>
  {% else %}
      <p>Tienes acceso limitado.</p>
  {% endif %}
{% else %}
  <p>Por favor, inicia sesión.</p>
{% endif %}

Uso de break

Aquí se usa break para salir del bucle cuando el índice es igual a 3, lo que evita mostrar más elementos después de ese punto.

bash
<ul>
  {% for item in lista %}
      {% if loop.index == 3 %}
          {% break %} {# Detiene el bucle si el índice es 3 #}
      {% endif %}
      <li>{{ item }}</li>
  {% endfor %}
</ul>

Uso de continue

Este ejemplo utiliza continue para omitir la impresión de los números pares de una lista, mostrando solo los números impares.

bash
<ul>
  {% for numero in lista %}
      {% if numero % 2 == 0 %}
          {% continue %} {# Omite los números pares #}
      {% endif %}
      <li>{{ numero }}</li> {# Solo muestra números impares #}
  {% endfor %}
</ul>
  Explicación

Uso de continue: En este caso, el bucle recorre cada numero en lista. Si el número es par (es decir, divisible entre 2), se utiliza continue para saltar a la siguiente iteración sin mostrarlo. Como resultado, solo se mostrarán los números impares en la lista.

Esto permite filtrar y mostrar solo aquellos elementos que cumplan ciertas condiciones.

Herencia de Plantillas en Jinja2


Base Template

La base de templates en Jinja2 actúa como una plantilla maestra que define la estructura general de las páginas de tu aplicación. Esta plantilla incluye bloques ({% block %}) que pueden ser sobreescritos por plantillas hijas, permitiendo así reutilizar el código y mantener una consistencia en el diseño.

html
{# Archivo base.html #}
<!DOCTYPE html>
<html>
<head>
  {% block head %}
  <title>{% block title %}{% endblock %} - Mi Sitio</title>
  {% endblock %}
</head>
<body>
  {% block content %}{% endblock %}
  {% block footer %}
  <footer>
      <p>&copy; Copyright 2024</p>
  </footer>
  {% endblock %}
</body>
</html>

Plantilla Hija

Las plantillas hijas en Jinja2 extienden una plantilla base (base.html) para reutilizar su estructura y personalizar su contenido. Al usar la herencia de plantillas, puedes definir el contenido específico que se insertará en los bloques de la plantilla base, manteniendo así un diseño coherente y modular.

bash
{# Archivo page.html #}  {# Nombre del archivo actual #}
{% extends "base.html" %}  {# Indica que esta plantilla extiende la plantilla base "base.html" #}

{# Define el contenido del bloque 'title', que se mostrará en la sección de título de la plantilla base #}
{% block title %}Página de Inicio{% endblock %}  

{% block content %}  {# Inicia el bloque 'content', donde se insertará el contenido específico de esta página #}
  <h1>Bienvenido</h1> 
  <p>Este es el contenido de la página</p>
{% endblock %}  
{# Finaliza el bloque 'content' #}

Organización de Plantillas

Organizar las plantillas en una estructura de carpetas permite un flujo de trabajo más limpio y fácil de mantener en Jinja2. La estructura jerárquica de archivos facilita la reutilización de componentes comunes y mejora la legibilidad del proyecto.

bash
templates/
├── base.html
├── components/
│   ├── header.html
│   ├── footer.html
│   └── forms.html
├── layouts/
│   ├── default.html
│   └── admin.html
└── pages/
  ├── home.html
  └── about.html

Reutilización de Componentes y Directivas


Directiva extends

En Jinja2, extends es una directiva que permite implementar herencia de plantillas, una característica que facilita la reutilización y organización del código en tus templates. Con extends, puedes crear una estructura base común que otras plantillas pueden heredar, reemplazando o completando secciones específicas sin duplicar código.

Plantilla Base (base.html)
html
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}Mi Sitio{% endblock %}</title>
</head>
<body>
  <header>
      <h1>Mi Sitio Web</h1>
  </header>
  
  <div id="content">
      {% block content %}{% endblock %}
  </div>
  
  <footer>
      <p>&copy; 2024 Mi Sitio</p>
  </footer>
</body>
</html>
Plantilla Hija (home.html)
bash
{% extends "base.html" %}

{% block title %}Página de Inicio{% endblock %}

{% block content %}
  <h2>Bienvenido a la página de inicio</h2>
  <p>Esta es la sección de contenido personalizada para la página de inicio.</p>
{% endblock %}
  Explicación

{% extends "base.html" %}: Indica que home.html es una plantilla hija que hereda la estructura de base.html. {% block title %} y {% block content %}: Estos bloques son áreas reemplazables en la plantilla base. La plantilla hija define su propio contenido para estos bloques.

Directiva de bloques (block)

Los bloques (block) en Jinja2 son secciones de una plantilla que se pueden definir y luego sobrescribir o completar en plantillas hijas. Los bloques funcionan junto con la directiva extends para hacer herencia de plantillas, permitiendo personalizar o expandir el contenido de una plantilla base.

¿Cómo Usar los Bloques (block) en Jinja2?

Los bloques se definen en la plantilla base usando {% block nombre_del_bloque %}{% endblock %}. Luego, las plantillas hijas pueden sobrescribir estos bloques con contenido específico, manteniendo la estructura general de la base.

Plantilla Hija (pagina_inicio.html)
bash
{% extends "base.html" %}

{% block title %}Página de Inicio{% endblock %}

{% block content %}
  <h2>Esta es la página de inicio</h2>
  <p>Bienvenido a la sección de inicio de nuestro sitio.</p>
{% endblock %}
  Explicación

Definición del bloque en la base: En base.html, se definen los bloques {% block title %} y {% block content %}. Estos bloques actúan como áreas “vacías” que las plantillas hijas pueden completar.

Personalización en la plantilla hija: En pagina_inicio.html, se utiliza {% block title %} y {% block content %} para proporcionar contenido específico que reemplaza el de la base.

Bloques personalizados (bloques de extensión)

son convenciones comunes en proyectos que usan Jinja2 para inyectar estilos CSS o scripts JavaScript adicionales en plantillas extendidas. Estas convenciones se usan cuando quieres agregar estilos o scripts específicos en algunas páginas sin modificar la plantilla base.

En la plantilla base, defines bloques como customCSS y customJS, que estarán vacíos por defecto, y en las plantillas que extienden la base, puedes sobreescribirlos para incluir los estilos o scripts adicionales que necesites.

Ejemplo de customCSS y customJS

1. Plantilla base (base.html):
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}Mi Aplicación{% endblock %}</title>

  <!-- Bloque para CSS personalizado -->
  {% block customCSS %}{% endblock %}
</head>
<body>
  <header>
      <h1>{% block header %}Encabezado principal{% endblock %}</h1>
  </header>
  <main>
      {% block content %}{% endblock %}
  </main>
  <footer>
      {% block footer %}Pie de página estándar{% endblock %}
  </footer>

  <!-- Bloque para JavaScript personalizado -->
  {% block customJS %}{% endblock %}
</body>
</html>
2. Plantilla extendida (pagina_especifica.html):
bash
{% extends "base.html" %}

{% block title %}Página Específica | Mi Aplicación{% endblock %}

{% block customCSS %}
  <style>
      body {
          background-color: #f0f0f0;
      }
      .especial {
          color: red;
          font-weight: bold;
      }
  </style>
{% endblock %}

{% block content %}
  <p class="especial">Este es un contenido especial para esta página.</p>
{% endblock %}

{% block customJS %}
  <script>
      document.addEventListener('DOMContentLoaded', function() {
          console.log('JavaScript personalizado cargado.');
      });
  </script>
{% endblock %}
  Explicación

  • En base.html, los bloques customCSS y customJS están definidos pero vacíos. Esto hace que no se incluya ningún estilo o script adicional a menos que los sobrescribas en una plantilla que extienda la base.
  • En pagina_especifica.html, la plantilla extiende base.html y usa customCSS para agregar un estilo de fondo y una clase especial, y customJS para incluir un script que muestra un mensaje en la consola.

Directiva Include

La directiva include en Jinja2 permite incluir otros templates o archivos HTML dentro de una plantilla. Esto es útil para reutilizar fragmentos de código (como encabezados, pies de página o barras laterales) en múltiples páginas, manteniendo tu código organizado y modular.

bash
{# Incluir un template parcial #}
{% include 'header.html' %}  {# Incluye el archivo 'header.html' en la plantilla actual #}
{% include 'sidebar.html' ignore missing %}  {# Incluye 'sidebar.html', y si el archivo no se encuentra, no se genera un error #}

Directiva Import

La directiva import en Jinja2 permite importar macros desde otros templates. Esto facilita la reutilización de fragmentos de código que realizan funciones específicas, como formularios o componentes de interfaz de usuario, promoviendo un código más limpio y organizado.

bash
{# Importar macros #}
{% import 'forms.html' as forms %}  {# Importa todas las macros del archivo 'forms.html' y las asigna al prefijo 'forms' #}
{{ forms.input('username') }}  {# Llama a la macro 'input' para generar un campo de entrada para el nombre de usuario #}

{# Importar con from #}
{% from 'forms.html' import input, textarea %}  {# Importa solo las macros 'input' y 'textarea' del archivo 'forms.html' #}
{{ input('username') }}  {# Llama a la macro 'input' directamente, sin el prefijo #}

Directiva Required

La directiva required en Jinja2 se utiliza en bloques de plantillas para asegurar que las plantillas hijas deben proporcionar una implementación para ese bloque. Esto ayuda a mantener la coherencia y garantiza que se definan secciones críticas en las plantillas que heredan de la base.

bash
{# Bloque requerido en plantillas hijas #}
{% block content required %}  {# Este bloque es obligatorio para las plantillas hijas #}
{% endblock %}

Directiva Set

La directiva set se utiliza para definir variables dentro de un template. Es útil para almacenar valores temporales que se utilizarán más adelante en el mismo template.

bash
{% set nombre = 'Urian' %}
<p>Hola, {{ nombre }}!</p>

Directiva With

La directiva with permite crear un contexto temporal donde puedes definir variables que estarán disponibles solo dentro del bloque with.

bash
{% with usuario = 'Maria' %}
  <p>Bienvenida, {{ usuario }}!</p>
{% endwith %}

Directiva Macro

Las macros son similares a las funciones en otros lenguajes de programación. Te permiten definir bloques de código reutilizables que pueden aceptar argumentos.

bash
{% macro saludo(nombre) %}
  <p>Hola, {{ nombre }}!</p>
{% endmacro %}

Filter

Los filtros en Jinja2 son funciones que se aplican a variables para modificar su salida. Puedes pensar en ellos como herramientas para transformar datos antes de que se muestren en la plantilla. Los filtros se aplican usando el símbolo | después de la variable.

bash
{{ nombre | upper }}  {# Convierte 'nombre' a mayúsculas #}
{{ texto | default('Sin información') }}  {# Muestra 'Sin información' si 'texto' está vacío o no está definido #}
{{ precio | round(2) }}  {# Redondea el precio a dos decimales #}

Recursos Adicionales

Documentación Oficial

Comunidad y Soporte