Вы находитесь на странице: 1из 16

Introducción a Jinja 2

El lenguaje Jinja 2.
Flask es únicamente un framework para ofrecer servicios basados en HTTP. Para poder
publicar contenidos dinámicos en HTML es necesario utilizar Jinja2.

Jinja es un lenguaje de plantillas (templates) escrito en Python, el cual permite insertar datos
procesados y texto predeterminado dentro de un documento de texto.

Jinja no sólo es utilizado por Flask. Algunos otros proyectos como Ansible lo utilizan para
crear playbooks en YAML.

En esta sección se explorarán las funcionalidades y características básicas de Jinja.


In [1]:
import jinja2

Sustitución de un texto con Jinja 2.


Jinja busca y sustituye dentro de un texto los nombres, expresiones y declaraciones que se
encuentran encerrados entre signos de llaves "{ }".

Expresiones.
Las expresiones deben estar encerradas entre llaves nuevamente "{ }".

Sintaxis:

{{ <expresión> }}

Declaraciones.
Las declaraciones deben estar encerradas entre signos de porcentajes "%".

Sintaxis:

{% <declaración> %}

...

...

{% endof<tipo de declaración> %}

Comentarios.
Las declaraciones deben estar encerradas entre signos de gato "#".

Sintaxis:

{# <comentario> #}

La clase jinja2.Template.
Esta clase crea objetos a partir del texto que se ingresa como parámetro que corresponden a
la plantilla sobre la que se van a ejecutar el código de sustitución.

Ejemplo:
In [2]:
plantilla = jinja2.Template("Hola, {{nombre}}.")

El método render().
Este método, al ser ejecutado desde un objeto instanciado de la clase jinja2.Template da por
resultado el texto procesado por la sintaxis de Jinja. Los argumentos que se ingresen en
formato <identificador> = <objeto> de forma susesiva y separados por comas serán
sustituidos cuando se les haga referencia.

Ejemplo:
In [3]:
plantilla = jinja2.Template("Hola,{{nombre}}.")
In [4]:
plantilla.render(nombre="Juan")
Out[4]:
'Hola,Juan.'

Expresiones.

Nombres, índices y atributos.


En vista de que Jinja 2 está basado en Python, es posible utilizar su sintaxis para acceder a
los elementos y/o atributos de un objeto que se utiliza como parámetro.

Ejemplos:
In [5]:
texto = "Hola, {{persona['nombre'].upper()}}."
In [6]:
plantilla = jinja2.Template(texto)
In [7]:
plantilla.render(persona={'nombre':'Jose', 'apellido': 'Pérez'})
Out[7]:
'Hola, JOSE.'

Filtros.
Un filtro en Jinja 2 es una especie de función que modifica al objeto resultante de una
expresión. Es posible consultar lo diversos filtros que ofrece Jinja en esta
liga: http://jinja.pocoo.org/docs/2.9/templates/#builtin-filters

Jinja 2 puede aplicar diversos filtros al texto que se ingresa mediante pipes usando la
siguiente sintaxis:

{{<expresión> | <filtro 1> | <filtro 2> |... | <filtro n>}}

De este modo, la salida de un filtro es la entrada del siguiente.

Ejemplos:

En estos ejemplos se utilizarán los filtros center y reverse de forma separada y posteriormente
combinada.
In [8]:
texto = "Hola, {{persona['nombre'].upper() | center(40)}}."
plantilla = jinja2.Template(texto)
plantilla.render(persona={'nombre':'Jose', 'apellido': 'Pérez'})
Out[8]:
'Hola, JOSE .'
In [9]:
texto = "Hola, {{persona['nombre'].upper() | reverse}}."
plantilla = jinja2.Template(texto)
plantilla.render(persona={'nombre':'Jose', 'apellido': 'Pérez'})
Out[9]:
'Hola, ESOJ.'
In [10]:
texto = "Hola, {{persona['nombre'].upper()| center(40)| reverse}}."
plantilla = jinja2.Template(texto)
plantilla.render(persona={'nombre':'Jose', 'apellido': 'Pérez'})
Out[10]:
'Hola, ESOJ .'

Declaraciones.
Una declaración corresponde a un bloque de código que se ejecuta y que incluye varias
expresiones con la siguiente sintaxis.
{% <declaración> %}

...

<texto y expresiones>

...

<% end<expresión correspondiente> %>

Jinja 2 puede utilizar expresiones de Python como:

 if, elif y else.


 for.
 with.

Los nombres y objetos definidos dentro de una declaración pertenecen exclusivamente al


ámbito de dicha declaración. Sólo los argumentos ingresados en el
método render() pertenecen al ámbito global.

Condicionales con if .
Jinja 2 permite el uso del condicionales if con la siguiente sintaxis:

{% _if_ <expresión lógica>%}

<Texto y código>

{% endif %}

Cabe hacer notar que los operadores lógicos de Python son los mismos que se utilizan para
las expresiones lógicas de este condicional.

Ejemplo:
In [11]:
texto = "Hola {{persona['nombre']}}.\
{% if persona['socio'] %}\
\nUsted es socio distinguido.\
{% endif %}"
In [12]:
print(texto)

Hola {{persona['nombre']}}.{% if persona['socio'] %}


Usted es socio distinguido.{% endif %}
In [13]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(persona={'nombre':'Jose', 'socio': True})
print(resultado)
Hola Jose.
Usted es socio distinguido.
In [14]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(persona={'nombre':'Juan', 'socio': False})
print(resultado)

Hola Juan.

Uso de else y elif en un condicional .

También es posible evaluar más de una expresión con la siguiente sintaxis:

{% _if_ <expresión lógica 1>%}

<Texto y código>

{% _elif_ <expresión lógica 2>%}

<Texto y código>

...

...

{% _elif_ <expresión lógica n>%}

<Texto y código>

{% _else %}

<Texto y código>

{% endif %}

Ejemplo:
In [15]:
texto = "Hola {{persona['nombre']}}.\n\
{% if persona['status'] == 'socio' %}\
Usted es socio distinguido.\
{% elif persona['status'] == 'cliente' %}\
Usted tiene una cuenta de cliente.\
{% else %}\
Por favor indique si es socio o cliente.\
{% endif %}"
In [16]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(persona={'nombre':'Jose', 'status': 'socio'}
)
print(resultado)

Hola Jose.
Usted es socio distinguido.
In [17]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(persona={'nombre':'Juan', 'status': 'cliente
'})
print(resultado)

Hola Juan.
Usted tiene una cuenta de cliente.
In [18]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(persona={'nombre':'Juan'})
print(resultado)

Hola Juan.
Por favor indique si es socio o cliente.

Validaciones adicionales.
Aemás de los operadores lógicos de Python, Jinja 2 cuenta con algunas otras validaciones
que pueden ser consultadas en esta liga: http://jinja.pocoo.org/docs/2.9/templates/#builtin-tests

Ejemplo:

Para este caso se utilizarán los validadores even y odd.


In [19]:
texto = "El número es {{numero}}.\n\
{% if numero is even %}\
Este número es par.\
{% elif numero is odd %}\
Este número es non.\
{% endif %}"
In [20]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(numero=4)
print(resultado)
El número es 4.
Este número es par.

Ciclos con for.


La evaluación de ciclos con for se comportan de forma idéntica a Python, pero con la siguiente
sintaxis:

{% for <elemento> in <iterable> %}

{{ <elemento> }}

{% endfor %}

Ejemplo: Se utilizará el ciclo for para una lista que a su vez contiene listas de dos elementos.
In [21]:
texto = "Enlaces recomendados:\n\
{%for nombre, liga in dato %}\
\n{{ nombre }}: {{ liga }} \
{% endfor %}"
In [22]:
ligas = [['slashdot', 'https://slashdot.org'],
['pythonista', 'https://pythonista.mx'],
['cloudevel', 'https://cloudevel.com']]
In [23]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render(dato=ligas)
print(resultado)

Enlaces recomendados:

slashdot: https://slashdot.org
pythonista: https://pythonista.mx
cloudevel: https://cloudevel.com

Macros.
Lo macros se comportan de forma similar a una función de Python y se definen con la
siguiente sintaxis:

{% macro <nombre> (<argumentos>) %}

<texto y código>
{% endmacro %}

Para invocar un macro se hace de la siguiente manera:

{{ <nombre>(<parámetros>) }}

Ejemplo:
In [24]:
texto = '{% macro suma (a, b=2) %}\
La suma es {{a + b}}.\n\
{% endmacro %}\
{{ suma(2)}}\
{{ suma(2, 3) }}'
In [25]:
plantilla = jinja2.Template(texto)
resultado = plantilla.render()
print(resultado)

La suma es 4.
La suma es 5.

Lectura de plantillas a partir de archivos.


La clase jinja.Template puede gestionar objetos de tipo str. Sin embargo, el verdadero
potencial de Jinja 2 está en el consumo de archivos de texto.

La clase jinja2.FileSystemLoader.
La clase jinja2.FileSystemLoader permite definir los parámetros necesarios para acceder a un
sistema de archivos, definiendo una o varias rutas en las que se encontrarán las plantillas.

Sintaxis:

jinja2.FileSystemLoader('<ruta>')

jinja2.FileSystemLoader(['<ruta 1>', '<ruta 2>', ..., '<ruta n


>'])

Ejemplo:*
In [26]:
%pwd
Out[26]:
'/home/oi/py201_Desarrollo_web_con_Flask'

Sustituir la ruta de arriba en la instrucción de abajo.


In [27]:
ruta = jinja2.FileSystemLoader('/home/oi/py201_Desarrollo_web_con_Flask/c
odigo')

La clase jinja2.Environment.
La clase jinja2.Environment permite definir la configuración de diversas propiedades de Jinja2,
incluyendo el parámetro loader el cual debe corresponder a un objeto instanciado de la
clase jinja2.FileSystemLoader.

Sintaxis:

<nombre> = jinja2.Environment(loader = <objeto de la clase jin


ja2.FileSystemLoader>, <otros parámetros>)

El objeto resultante contiene al método get_template(), el cual permite acceder a una archivo
cuyo nombre o ruta relativa se ingresa como parámetro.

Jinja 2 buscará el archivo desde las rutas definidas previamente.

Sintaxis:

<nombre>.get_template('<ruta relativa del archivo>')

El resultado es un objeto similar al de jinja2.Template.

Ejemplo: El archivo codigo/plantilla.html contiene el siguiente código:

<!DOCTYPE html>

<html>

<head>

<title>Bienvenidos </title>

</head>

<body>

<h1>Listado de referencias</h1>

<ul>

{% for nombre, liga in lista %}


<li><a href='{{ liga }}'> {{ nombre.capitalize() }}</a></li
>

<ul>

{% endfor %}

</body>

In [28]:
ligas = [['slashdot', 'https://slashdot.org'],
['pythonista', 'https://pythonista.mx'],
['cloudevel', 'https://cloudevel.com']]
In [29]:
%pwd
Out[29]:
'/home/oi/py201_Desarrollo_web_con_Flask'

Sustituir la ruta de arriba en el código de abajo.


In [30]:
entorno = jinja2.Environment(loader=jinja2.FileSystemLoader('/home/oi/py2
01_Desarrollo_web_con_Flask/codigo'))
plantilla = entorno.get_template("plantilla.html")
In [31]:
print(plantilla)

<Template 'plantilla.html'>
In [32]:
print(plantilla.render(lista=ligas))

<!DOCTYPE html>
<html>
<head>
<title>Bienvenidos </title>
</head>
<body>
<h1>Listado de referencias</h1>
<ul>

<li><a href='https://slashdot.org'> Slashdot</a></li>

<li><a href='https://pythonista.mx'> Pythonista</a></li>

<li><a href='https://cloudevel.com'> Cloudevel</a></li>


<ul>
</body>

Importación de macros.
Es posible importar un macro desde una plantilla mediante la siguiente sintaxis:

{% from <ruta del archivo en fornato str> import <nombre del m


acro>

Ejemplo:

El archivo codigo/sumadora.txt contiene la siguiente plantilla:

{% macro suma (a, b=2) %}

La suma es {{a + b}}.

{% endmacro %}

l archivo codigo/importadora.txt contiene la siguiente plantilla:

{% from "sumadora.txt" import suma %}\

{{ suma(3, 4) }}

In [33]:
%pwd
Out[33]:
'/home/oi/py201_Desarrollo_web_con_Flask'

Sustituir la ruta de arriba en el código de abajo.


In [34]:
entorno = jinja2.Environment(loader=jinja2.FileSystemLoader('/home/oi/py2
01_Desarrollo_web_con_Flask/codigo'))
plantilla = entorno.get_template("importadora.txt")
In [35]:
print(plantilla.render())

La suma es 7.

Herencia de plantillas.
Jinja 2 tiene la capacidad de aprovechar plantillas que pueden ser modificadas utilizando el
concepto de bloques.

Bloques.
Los bloques son elementos que delimitan una porción de texto y alos que se les asigna un
nombre. Utilizan la siguiente sintaxis:

{% block <nombre> %}

...

...

{% endblock% }

Los bloques pueden ser anidados.

La porción de texto delimitada por los bloques pueden ser insertada en cualquier otra parte
invocándolos de la siguiente manera:

{% block <nombre> %}

Herencia con extends.


Es posible crear una nueva plantilla partir de mediante la siguiente sintaxis:

{% extends '<ruta de la platilla de origen>' %}

Esto traerá consigo el contenido completo de la plantilla de origen y es posible sobrescribir los
bloques simpremente redefiniéndolos.

Ejemplo de uso de bloques y herencia.

El archivo codigo/plantilla_base.html contiene el siguiente código.

<!DOCTYPE html>

<html>

<head>

{% block head %}

<link rel="stylesheet" href="style.css" />

<title>Bienvenidos a {% block title%}Pythonista{% endblock


%}</title>
{% endblock %}

</head>

<body>

<div id="content">{% block content %}Hola, Bienvenidos.{%


endblock %}</div>

<div id="footer">

{% block footer %}

&copy; Copyright 2018 <a href="https://pythonista.mx/"


>Pythonista®.</a>.

{% endblock %}

</div>

</body>

In [36]:
%pwd
Out[36]:
'/home/oi/py201_Desarrollo_web_con_Flask'

Nota: Verificar que la ruta actual corresponde a la que se indica en la celda de de abajo.
In [37]:
entorno = jinja2.Environment(loader=jinja2.FileSystemLoader('/home/oi/py2
01_Desarrollo_web_con_Flask/codigo'))
plantilla = entorno.get_template("plantilla_base.html")
print(plantilla.render())

<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="style.css" />


<title>Bienvenidos a Pythonista</title>

</head>
<body>
<div id="content">Hola, Bienvenidos.</div>
<div id="footer">

&copy; Copyright 2017 <a href="https://pythonista.mx/">Pythonista


®.</a>.
</div>
</body>

El archivo codigo/plantilla_hija.html contiene el siguiente código, el cual hereda el código del


archivo plantilla_base.html.

{% extends "plantilla_base.html" %}

{% block title %} Cloudevel {%endblock %}

{% block footer %}

&copy; Copyright 2017 <a href="https://cloudevel.com/">Clo


udevel.</a>.

{% endblock %}

Nota: Verificar que la ruta actual corresponde a la que se indica en la celda de de abajo.
In [38]:
entorno = jinja2.Environment(loader=jinja2.FileSystemLoader('/home/oi/py2
01_Desarrollo_web_con_Flask/codigo'))
plantilla = entorno.get_template("plantilla_hija.html")
resultado = plantilla.render()
print(resultado)

<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="style.css" />


<title>Bienvenidos a Cloudevel </title>

</head>
<body>
<div id="content">Hola, Bienvenidos.</div>
<div id="footer">

&copy; Copyright 2017 <a href="https://cloudevel.com/">Cloudevel.</a>


.

</div>
</body>

Flask y Jinja 2.
Flask utiliza por defecto las plantillas de Jinja 2 mediante el módulo flask.render_template().

Del mismo modo, está configurado para buscar los archivos de plantilla en el
subdirectorio templates localizado en el directorio desde el que se está corriendo flask.

Ejemplo: Se desplegará una página HTML generada a partir de la plantilla localizada


en templates/plantilla.html, la cual contiene lo siguiente:

<!DOCTYPE html>

<html>

<head>

<title>Bienvenidos </title>

</head>

<body>

<h1>Listado de referencias</h1>

<ul>

{% for nombre, liga in lista %}

<li><a href='{{ liga }}'> {{ nombre.capitalize() }}</a></li


>

{% endfor %}

<ul>

</body>

In [39]:
%ls templates

alumno_carrera.html captura_alumno.html plantilla_formas_avanzadas.h


tml
busqueda_avanzada.html despliega.html plantilla_formas.html
busqueda.html _formhelpers.html plantilla.html

La función de vista inicio() desplegará la plantilla plantilla.html incluyendo al objeto de


tipo list con el nombre ligas.

La página peude ser vista desde: http://localhost:5000/

Advertencia: Una vez ejecutada la siguente celda, es necesario reiniciar el kernel de Jupyter
para poder ejecutar el resto de las celdas de la notebook.
In [ ]:
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def inicio():

ligas = [['slashdot', 'https://slashdot.org'],


['pythonista', 'https://pythonista.io'],
['cloudevel', 'https://cloudevel.com']]

return render_template('plantilla.html', lista=ligas)

#Si no se define el parámetro host, flask sólo será visible desde localho
st
app.run(host='0.0.0.0')

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

La vista desde un navegador es la siguiente:

Вам также может понравиться