Variables y expresiones básicas
Jinja2 utiliza una sintaxis de delimitadores específicos para distinguir entre el contenido estático HTML y las expresiones dinámicas que se procesan en el servidor. Esta separación permite crear templates flexibles que combinan estructura HTML fija con datos variables.
La sintaxis fundamental de Jinja2 se basa en tres tipos de delimitadores principales que definen diferentes comportamientos:
{{ expresión }}
- Para mostrar valores y expresiones{% declaración %}
- Para estructuras de control y lógica{# comentario #}
- Para comentarios que no aparecen en el HTML final
Renderizado de variables simples
Las variables simples se renderizan utilizando la sintaxis de dobles llaves. Cuando el motor de templates encuentra esta sintaxis, busca la variable en el contexto pasado desde FastAPI y la sustituye por su valor:
<h1>Bienvenido, {{ nombre }}</h1>
<p>Tu edad es {{ edad }} años</p>
<p>Email de contacto: {{ email }}</p>
Desde FastAPI, estas variables se pasan mediante el diccionario de contexto:
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/perfil/{usuario}")
async def mostrar_perfil(request: Request, usuario: str):
contexto = {
"request": request,
"nombre": usuario.title(),
"edad": 28,
"email": f"{usuario}@ejemplo.com"
}
return templates.TemplateResponse("perfil.html", contexto)
Acceso a propiedades y atributos
Jinja2 permite acceder a propiedades de objetos y elementos de diccionarios usando la notación de punto o corchetes. Esta flexibilidad facilita el trabajo con estructuras de datos complejas:
<!-- Acceso con notación de punto -->
<h2>{{ usuario.nombre }}</h2>
<p>Departamento: {{ usuario.trabajo.departamento }}</p>
<!-- Acceso con corchetes (útil para claves dinámicas) -->
<p>Rol: {{ usuario['rol'] }}</p>
<p>Configuración: {{ config['tema_oscuro'] }}</p>
Ejemplo de contexto correspondiente desde FastAPI:
@app.get("/dashboard")
async def dashboard(request: Request):
usuario_data = {
"nombre": "Ana García",
"trabajo": {
"departamento": "Desarrollo",
"puesto": "Senior Developer"
},
"rol": "administrador"
}
contexto = {
"request": request,
"usuario": usuario_data,
"config": {"tema_oscuro": True}
}
return templates.TemplateResponse("dashboard.html", contexto)
Expresiones aritméticas y operaciones
Jinja2 soporta expresiones aritméticas básicas directamente en el template, permitiendo realizar cálculos simples sin necesidad de preprocesar los datos en el backend:
<!-- Operaciones aritméticas básicas -->
<p>Precio base: {{ precio }} €</p>
<p>IVA (21%): {{ precio * 0.21 }} €</p>
<p>Precio final: {{ precio + (precio * 0.21) }} €</p>
<!-- Operaciones con variables -->
<p>Total productos: {{ cantidad_a + cantidad_b + cantidad_c }}</p>
<p>Promedio: {{ (nota1 + nota2 + nota3) / 3 }}</p>
Las operaciones de comparación también se pueden utilizar dentro de las expresiones de renderizado:
<p>Estado: {{ "Activo" if usuario.activo else "Inactivo" }}</p>
<p>Descuento aplicable: {{ "Sí" if edad >= 65 else "No" }}</p>
<span class="{{ 'text-success' if puntuacion > 80 else 'text-warning' }}">
Puntuación: {{ puntuacion }}
</span>
Operaciones con cadenas de texto
El motor de templates permite concatenación y manipulación básica de strings directamente en las expresiones:
<!-- Concatenación de strings -->
<h1>{{ saludo + ", " + nombre + "!" }}</h1>
<!-- Interpolación con formato -->
<p>Archivo: {{ nombre_archivo + "." + extension }}</p>
<p>URL completa: {{ "https://api.ejemplo.com/usuarios/" + str(id_usuario) }}</p>
<!-- Combinación con operador ternario -->
<p>{{ "Dr. " + apellido if es_doctor else "Sr. " + apellido }}</p>
Trabajo con listas y acceso por índice
Jinja2 facilita el acceso a elementos específicos de listas y la visualización de propiedades de colecciones:
<!-- Acceso por índice -->
<p>Primer elemento: {{ lista_productos[0] }}</p>
<p>Último elemento: {{ lista_productos[-1] }}</p>
<!-- Propiedades de listas -->
<p>Total de productos: {{ lista_productos|length }}</p>
<p>Lista vacía: {{ "Sí" if lista_productos|length == 0 else "No" }}</p>
<!-- Elementos anidados -->
<h3>{{ productos[0].nombre }}</h3>
<p>Precio: {{ productos[0].precio }} €</p>
Expresiones condicionales inline
Las expresiones ternarias permiten incluir lógica condicional simple directamente en el punto de renderizado, manteniendo los templates limpios:
<!-- Sintaxis: valor_si_true if condicion else valor_si_false -->
<span class="{{ 'badge-success' if stock > 10 else 'badge-danger' }}">
Stock: {{ stock }}
</span>
<p>Estado de envío: {{ "Gratis" if total > 50 else "5€" }}</p>
<!-- Condiciones múltiples -->
<div class="{{ 'alert-success' if status == 'completado'
else 'alert-warning' if status == 'pendiente'
else 'alert-danger' }}">
{{ mensaje }}
</div>
Escape automático y contenido seguro
Por defecto, Jinja2 aplica escape automático a las variables para prevenir ataques XSS. Sin embargo, es importante entender cómo manejar contenido HTML cuando sea necesario:
<!-- Escape automático (comportamiento por defecto) -->
<p>{{ mensaje_usuario }}</p> <!-- Los < > se convierten en < > -->
<!-- Contenido HTML confiable (usar con precaución) -->
<div>{{ contenido_html|safe }}</div>
<!-- Alternativa más explícita -->
<div>{{ contenido_html|markup }}</div>
Esta funcionalidad de escape es especialmente relevante cuando se muestran datos introducidos por usuarios o contenido que puede contener caracteres especiales HTML.
Filtros más comunes
Los filtros en Jinja2 son funciones que transforman y formatean variables antes de mostrarlas en el template. Se aplican utilizando el símbolo pipe (|
) después de la variable, permitiendo modificar su presentación sin alterar los datos originales en el contexto.
Filtros de formato de texto
Los filtros de texto son fundamentales para controlar la presentación de cadenas de caracteres en las interfaces web:
<!-- Transformaciones de caso -->
<h1>{{ titulo|title }}</h1> <!-- Primera Letra De Cada Palabra -->
<p>{{ nombre|upper }}</p> <!-- MAYÚSCULAS -->
<p>{{ descripcion|lower }}</p> <!-- minúsculas -->
<p>{{ codigo|capitalize }}</p> <!-- Solo primera mayúscula -->
<!-- Limpieza y formato -->
<p>{{ mensaje|trim }}</p> <!-- Elimina espacios al inicio/final -->
<p>{{ texto_largo|truncate(50) }}</p> <!-- Corta el texto a 50 caracteres -->
<p>{{ url_slug|replace('-', ' ') }}</p> <!-- Reemplaza guiones por espacios -->
Ejemplo práctico desde FastAPI:
@app.get("/articulo/{slug}")
async def mostrar_articulo(request: Request, slug: str):
articulo_data = {
"titulo": "guía completa de fastapi",
"autor": " juan pérez ",
"contenido": "Este es un texto muy largo que necesita ser truncado para la vista previa del artículo...",
"slug": "guia-completa-de-fastapi"
}
contexto = {
"request": request,
**articulo_data
}
return templates.TemplateResponse("articulo.html", contexto)
Filtros numéricos y de formato
Los filtros numéricos facilitan la presentación de números, precios y cantidades de forma legible:
<!-- Formato numérico -->
<p>Precio: {{ precio|round(2) }} €</p> <!-- Redondea a 2 decimales -->
<p>Cantidad: {{ stock|int }}</p> <!-- Convierte a entero -->
<p>Porcentaje: {{ tasa|float * 100 }}%</p> <!-- Convierte a float -->
<!-- Formateo de números grandes -->
<p>Visitas: {{ visitas|filesizeformat }}</p> <!-- 1.5 MB, 2.3 KB, etc -->
<p>Total: {{ total|floatformat(2) }}</p> <!-- Formato decimal fijo -->
<!-- Valores absolutos y matemáticos -->
<p>Diferencia: {{ diferencia|abs }}</p> <!-- Valor absoluto -->
<p>Mínimo: {{ [precio_a, precio_b, precio_c]|min }}</p>
<p>Máximo: {{ [precio_a, precio_b, precio_c]|max }}</p>
Filtros de fecha y tiempo
Aunque FastAPI puede manejar fechas en el backend, Jinja2 ofrece filtros básicos para formatear información temporal:
<!-- Formateo de fechas (requiere objetos datetime) -->
<p>Fecha: {{ fecha|strftime('%d/%m/%Y') }}</p>
<p>Hora: {{ timestamp|strftime('%H:%M') }}</p>
<!-- Información de tiempo -->
<small>Publicado hace {{ dias_transcurridos }} días</small>
<span>{{ "Nuevo" if dias_transcurridos < 7 else "Reciente" if dias_transcurridos < 30 else "Archivo" }}</span>
Filtros de colecciones
Los filtros de listas y diccionarios son especialmente útiles para procesar conjuntos de datos en los templates:
<!-- Información sobre colecciones -->
<p>Total productos: {{ productos|length }}</p>
<p>Primera categoría: {{ categorias|first }}</p>
<p>Última actualización: {{ fechas|last }}</p>
<!-- Ordenamiento y selección -->
<h3>Productos más caros:</h3>
{% for producto in productos|sort(attribute='precio', reverse=true) %}
<p>{{ producto.nombre }}: {{ producto.precio }}€</p>
{% endfor %}
<!-- Filtrado básico -->
<h3>Productos en stock:</h3>
{% for item in productos|selectattr('stock', 'greaterthan', 0) %}
<p>{{ item.nombre }} - Stock: {{ item.stock }}</p>
{% endfor %}
Filtros de validación y control
Los filtros de comprobación permiten evaluar el estado de las variables y manejar valores por defecto:
<!-- Valores por defecto -->
<p>Nombre: {{ usuario.nombre|default('Usuario anónimo') }}</p>
<p>Bio: {{ perfil.biografia|default('Sin biografía disponible') }}</p>
<!-- Comprobación de existencia -->
{% if usuario.avatar %}
<img src="{{ usuario.avatar }}" alt="Avatar">
{% else %}
<img src="{{ '/static/img/default-avatar.png'|default('/static/img/placeholder.png') }}" alt="Avatar por defecto">
{% endif %}
<!-- Filtros de tipo -->
<p>Es lista: {{ "Sí" if datos is iterable else "No" }}</p>
<p>Es número: {{ "Sí" if edad is number else "No" }}</p>
Filtros de escape y seguridad
Complementando el escape automático mencionado anteriormente, estos filtros de seguridad ofrecen control específico sobre el contenido:
<!-- Control de escape explícito -->
<div>{{ contenido_confiable|safe }}</div>
<p>{{ entrada_usuario|e }}</p> <!-- Escape forzado -->
<!-- URLs y enlaces -->
<a href="{{ enlace|urlencode }}">{{ texto_enlace|e }}</a>
<p>Slug: {{ titulo|slugify }}</p> <!-- Convierte a URL-friendly -->
<!-- Atributos HTML -->
<div class="{{ clases|join(' ') }}"> <!-- Une lista con espacios -->
{{ contenido }}
</div>
Filtros personalizados en cadena
Una característica importante de Jinja2 es la capacidad de encadenar múltiples filtros, aplicándolos secuencialmente de izquierda a derecha:
<!-- Cadena de transformaciones -->
<h1>{{ titulo|trim|title|replace(' ', '-')|lower }}</h1>
<!-- Procesamiento complejo -->
<p>{{ descripcion|trim|truncate(100)|title }}</p>
<!-- Formateo de listas -->
<p>Tags: {{ tags|join(', ')|title }}</p>
<p>Autores: {{ autores|map(attribute='nombre')|join(' y ') }}</p>
Filtros condicionales avanzados
Los filtros se pueden combinar con expresiones condicionales para crear lógica de presentación sofisticada:
<!-- Filtros condicionales -->
<span class="{{ 'text-success' if stock|int > 0 else 'text-danger' }}">
{{ "Disponible" if stock|int > 0 else "Agotado" }}
</span>
<!-- Formateo condicional de precios -->
<p class="precio">
{{ precio|round(2) if precio > 0 else "Gratis" }}
{{ "€" if precio > 0 }}
</p>
<!-- Manejo de listas vacías -->
{% if productos|length > 0 %}
<p>Mostrando {{ productos|length }} productos</p>
{% else %}
<p>{{ "No hay productos disponibles"|upper }}</p>
{% endif %}
Esta funcionalidad de filtros convierte a Jinja2 en una herramienta flexible para la presentación de datos, permitiendo mantener la lógica de formato en el template mientras se conserva la separación entre datos y presentación.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en FastAPI
Documentación oficial de FastAPI
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, FastAPI es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de FastAPI
Explora más contenido relacionado con FastAPI y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la sintaxis fundamental de Jinja2 y sus delimitadores.
- Aprender a renderizar variables simples y acceder a propiedades de objetos y diccionarios.
- Utilizar expresiones aritméticas, condicionales y manipulación básica de cadenas en templates.
- Aplicar filtros comunes para formatear texto, números, fechas y colecciones.
- Entender el manejo de seguridad mediante escape automático y filtros de escape explícito.