Blog
¿Que son las Plantillas en flask?
Ya tenemos nuestra app básica de Flask que saluda a todo aquel que la visite. Esta app evolucionará y se convertirá en un pequeño blog. Para esto, sería ideal que la pagina de inicio tenga un saludo personalizado para cada usuario. Para eso crearemos un usuario simulado (ignoraremos el hecho de que la aplicación no tiene definido el concepto de usuario todavía). Para crear este usuario, utilizaremos un diccionario sencillo:
usuario = {'nombre':'Fede'}
Los usuarios simulados son una herramienta muy útil que permite que el desarrollador se concentre en una parte de la aplicación sin tener que preocuparse de partes que no hayan sido desarrolladas. Por ejemplo, a continuación desarrollaremos la pagina de inicio de la aplicación, y no nos detendremos por el hecho de que aun no estén definidos los usuarios, dejando esa parte para otro momento.
La función view en nuestra app devuelve un string sencillo. Queremos ahora que, en lugar de devolver un string, devuelva una pagina HTML completa. Abrimos el archivo “rutas.py” y le agregamos la siguiente modificación:
from app import app from flask import render_template @app.route('/') @app.route('/index') def index(): usuario = {'nombre':'Fede'} return ''' <html> <head> <title>Blog de Prueba</title> </head> <body> <h1>Hola '''+ usuario['nombre'] + '''!</h1> </body> </html>'''
Es recomendable que saber un poco de HTML para este curso.
Cuando abrimos nuevamente localhost, nos debería cargar algo similar a esto:
Lógicamente, esta forma de hacer que el HTML llegue al explorador es muy poco eficiente. Si se considera la complejidad que puede llegar a tener una pagina web, esta práctica no es sustentable, y más aún, cuando las páginas del blog de cada usuario estarán en constante cambio. La aplicación necesitará entonces mas funciones view que estarán asociadas con mas URLs, para evitar entonces tener que editar el HTML de cada función, todas las veces que se quiera hacer un cambio en la interfaz de la aplicación.
Si se pueden mantener separadas la lógica de la app y la interfaz, todo estará mejor organizado. Tendrías incluso la opción de contratar un diseñador web que se encargue del frontend (la parte que se ve), mientras nos encargamos de desarrollar la parte lógica.
Aquí es donde entran en acción las plantillas. Las plantillas ayudan a lograr esta separación entre las partes de la app. En Flask, las plantillas son archivos separados que se guardan en una carpeta llamada templates (plantillas en ingles) que va dentro de la carpeta de la aplicación. Entonces, una vez que estemos en el directorio principal, debemos crear el directorio templates:
(env) $ mkdir app/templates
Dentro de este directorio, debemos crear un archivo que se llame “index.html” y debe tener la siguiente información:
<html> <head> <title>{{ titulo }} - Blog</title> </head> <body> <h1>¡Hola, {{ usuario.nombre }}!</h1> </body> </html>
Esta es una pagina muy básica. Lo interesante de esto, son las llaves que tienen el contenido dinámico. Estas llaves representan las partes de la página que son variables, y que cambian cada vez que se visita la página.
Ya que tenemos nuestra plantilla HTML lista, tenemos que modificar la funcion view:
from app import app from flask import render_template @app.route('/') @app.route('/index') def index(): usuario = {'nombre':'fede'} return render_template('index.html', titulo="Inicio", usuario=usuario)
Mucho mas simple y ordenado, ¿cierto?
Si ejecutamos esta versión, debería de aparecer algo similar a esto:
La operación que convierte una plantilla en una pagina se llama renderizado. Con la función render_template(), renderizamos. Esta función es parte de Flask. Toma como argumento el nombre de la plantilla y una lista de variables que serán utilizadas en la página y la devuelve con todas las variables en el lugar que van.
La función render_template() invoca al motor de de plantillas Jinja2, el cual viene incluido en Flask también. Jinja2 sustituye todo aquello que esté dentro de llaves ({{ }}) con su valor correspondiente, según los argumentos pasados a render_template().
Condicionales
Vimos como Jinja2 renderiza las variables en las plantillas, pero esto es solo una de muchas operaciones que puede hacer. Jinja2, tiene también soporte para condicionales (if, while) dentro de llaves con el símbolo de porcentaje {% %}, escribamos el siguiente código en nuestra plantilla index.html:
<html> <head> {% if titulo %} <title>{{ titulo }} - Blog</title> {% else %} <title>Blog</title> {% endif %} </head> <body> <h1>¡Hola, {{ usuario.nombre }}!</h1> </body> </html>
Ahora, la plantilla es un poco mas “inteligente”. Si no se pasa un titulo a la funcion render_template(), en lugar de dejar el espacio en blanco, muestra un título por defecto. Se puede probar borrando el título de la función render_template().
Ciclos
En un blog, los usuarios generalmente querrán ver las publicaciones mas recientes de otros usuarios, en la página de inicio. Para esto, utilizaremos nuevamente objetos simulados. Abrimos el archivo “rutas.py” y le agregamos lo siguiente:
from app import app from flask import render_template @app.route('/') @app.route('/index') def index(): usuario = {'nombre':'fede'} pubs = [ { 'autor':{'usuario':'Juan'}, 'pub':'Bonito dia en Barcelona' }, { 'autor':{'usuario':'Maria'}, 'pub':'Hoy tuve una buena tarde en el cine' } ] return render_template('index.html', titulo="Inicio", usuario=usuario, pubs=pubs)
Tenemos las publicaciones en una lista llamada pubs, y cada publicación es un diccionario con su autor y el cuerpo de la publicación. Cuando esté implementando realmente las publicaciones en la app, es recomendable que se conserven los nombres de las variables que estamos utilizando (autor, pub) para que no se pierda el trabajo que adelantemos con los usuarios simulados.
Luego, tenemos que ir a la plantilla y aplicar los cambios pertinentes para que las publicaciones sean mostradas. Como la lista de publicaciones puede ser muy grande, tenemos que definir de manera adecuada la funcion view para que decida cuantas publicaciones serán mostradas. La plantilla no puede asumir nada por su cuenta, y debe estar preparada para mostrar cualquier número de publicaciones. Para esto Jinja2 cuenta con ciclos for. Vamos a la carpeta templates y modificamos el archivo “index.html” con la siguiente información:
<html> <head> {% if titulo %} <title>{{ titulo }} - Blog</title> {% else %} <title>Blog</title> {% endif %} </head> <body> <h1>¡Hola, {{ usuario.nombre }}!</h1> {% for pub in pubs %} <div><p>{{ pub.autor.usuario }} Twitteó: <b>{{ pub.pub }}</b></p></div> {% endfor %} </body> </html>
Sencillo, ¿cierto?
Si probamos esta versión nueva, debería aparecer algo como esto:
Herencia de plantillas
La mayoría de aplicaciones web de la actualidad, tienen una barra de navegación en la parte superior de la página, con enlaces usados frecuentemente (p. ej: en Facebook tenemos el botón de inicio, el botón de perfil, etc). Podemos añadir una barra de navegación al archivo “index.html” con unas pocas lineas de código extra, pero, cuando nuestra app sea mas grande, necesitaremos la misma barra de navegación en otras páginas. Como no queremos estár copiando/pegando el código de la barra de navegación muchas veces en muchas plantillas, utilizaremos entonces la herencia de plantillas, siguiendo la linea de pensamiento DRY (acrónimo de Don’t Repeat Yourself, que en español significa “no te repitas”).
Jinja2 tiene una característica que facilita la herencia de plantillas. Esencialmente, lo que haremos es mover las partes que son comunes en la interfaz de la página a una plantilla base, de donde se derivarán las demás.
Creamos un archivo llamado “base.html” dentro de la carpeta templates, el cual tendrá la barra de navegación y algunos de los detalles implementados anteriormente:
<html> <head> {% if titulo %} <title>{{ titulo }} - Unipython Tweet</title> {% else %} <title>Unipython Tweet</title> {% endif %} </head> <body> <div>Blog: <a href="/index">Inicio</a></div> <hr> {% block contenido %}{% endblock %} </body> </html>
La linea “block contenido” define el bloque en donde será insertado el contenido de las plantillas derivadas. Los Bloques tienen nombres únicos, los cuales son utilizados por las plantillas derivadas para entregar su contenido.
Con la plantilla “base.html” lista, procedemos ahora a simplificar “index.html” con la herencia de plantillas correspondiente:
{% extends "base.html" %} {% block contenido %} <h1>¡Hola, {{ usuario.nombre }}!</h1> {% for pub in pubs %} <div><p>{{ pub.autor.usuario }} Twitteó: <b>{{ pub.pub }}</b></p></div> {% endfor %} {% endblock %}
Como base.html se hará cargo de la estructura general de la página, se eliminaron de index.html todos los elementos que no sean contenido. Las expresiones “extends” establecen la herencia entre plantillas, de forma que Jinja2 sabe que index.html debe ser expandida dentro de “base.html”. Ambas plantillas tienen la expresión block con el nombre contenido, de forma que Jinja2 sabe como combinar ambas plantillas en una sola. De esta forma, si necesitamos mas paginas para la aplicación, se pueden crear como plantillas derivadas de la misma base, y de esta forma, todas las paginas tendrán la misma apariencia sin necesidad de repetir las cosas.
➡ Continúa aprendiendo con nuestro Curso de Flask – Python:
Muchas gracias. ?Como puedo iniciar sesion?