Iniciar la aplicación
Crea una carpeta llamada app, que alojará la aplicación.
(venv) $ mkdir appDentro crea un fichero con nombre __init__.py con el siguiente código:
from flask import Flask
app = Flask(__name__)
from app import routes- Se crea el objeto de la aplicación como una instancia de una clase
Flaskimportada del paquete flask. - La variable
__name__que se pasa a la claseFlaskes una variable predefinida de Python, cuyo nombre corresponde al del módulo en el que se utiliza. - En la práctica, pasar esta variable
__name__casi siempre configurará Flask correctamente. A continuación, la aplicación importa el móduloroutes, que aún no existe.
Un aspecto que puede resultar confuso al principio es que existen dos entidades con el mismo nombre app.
- El paquete
appque se define mediante el directorio de la aplicación y el script__init__.py, y se hace referencia a él en la declaraciónfrom app import routes. - La variable
appque se define como una instancia de la claseFlasken el script__init__.py, lo que la convierte en miembro del paqueteapp.
Otra particularidad es que el módulo routes se importa al final del script y no al principio, como se hace habitualmente. La importación al final es una solución conocida que evita las importaciones circulares , un problema común en las aplicaciones Flask. Verás que el módulo routes necesita importar la variable app definida en este script, por lo que colocar una de las importaciones recíprocas al final evita el error que resulta de las referencias mutuas entre estos dos archivos.
Modulo routes
Las rutas gestionan las diferentes URL que admite la aplicación. En Flask, los manejadores de las rutas de la aplicación se escriben como funciones de Python, llamadas view funtions. Estas funciones se asocian a una o más URL de ruta para que Flask sepa qué lógica ejecutar cuando un cliente solicita una URL determinada.
Aquí está la primera función de vista para esta aplicación, que debes escribir en un nuevo módulo llamado routes.py
from app import app
@app.route('/')
@app.route('index')
def index():
return "Hello, World"Las dos líneas @app.route son decoradores , una característica única del lenguaje Python. Un decorador modifica la función que le sigue. Un patrón común con los decoradores es usarlos para registrar funciones como devoluciones de llamada para ciertos eventos.
En este caso, el decorador @app.route crea una asociación entre la URL proporcionada como argumento y la función. Esto significa que cuando un navegador web solicita cualquiera de estas dos URL, Flask invocará esta función y devolverá su valor de retorno al navegador como respuesta.
Para completar la aplicación, necesitas tener un script de Python en el nivel superior que defina la instancia de la aplicación Flask. Llamemos a este script microblog.py y definámoslo como una sola línea que importe la instancia de la aplicación:
from app import app¿Recuerdas las dos entidades app? Aquí puedes verlas juntas en la misma oración.
- La instancia de la aplicación Flask se llama
appy pertenece al paqueteapp. - La instrucción
from app import appimporta la variableappque pertenece al paqueteapp. Si te resulta confuso, puedes cambiar el nombre del paquete o de la variable.
Para asegurarnos de que todo se está haciendo correctamente, a continuación se muestra un diagrama de la estructura del proyecto hasta el momento:
microblog/
venv/
app/
__init__.py
routes.py
microblog.pyLa aplicación está lista, solo hace falta llamarla:
flask --app microblog.py --debug runTemplates
Las plantillas ayudan a lograr la separación entre la presentación y la lógica de negocio. En Flask, las plantillas se escriben como archivos separados, almacenados en una carpeta llamada templates dentro del paquete de la aplicación.
archivo index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{{title}}</title>
</head>
<body>
<h1>Hello, {{user.username}}!</h1>
</body>
</html>Los marcadores de posición {{ … }} representan las partes de la página que son variables y se cargan en el momento de la ejecución. Ahora que usamos las plantillas, podemos eliminar el texto de la función index() y agregar la plantilla.
from flask import render_template
from app import app
@app.route('/')
@app.route('/index')
def index():
user = {'username': 'Miguel'}
return render_template('index.html', title='Home', user=user)La operación que convierte una plantilla en una página HTML completa se llama renderizado . Para renderizar la plantilla, importa una función Flask llamada render_template(). Esta función realiza esta acción:
- Busca el archivo
templates/index.html - Sustituye las variables Jinja2
- Devuelve el HTML generado al navegador
La función render_template() invoca el motor de plantillas Jinja que viene incluido con el framework Flask. Jinja sustituye los bloques {{ ... }} con los valores correspondientes, proporcionados por los argumentos en la llamada render_template().
Declaraciones condicionales
Ya has visto cómo Jinja reemplaza los marcadores de posición con valores reales durante la renderización, pero esta es solo una de las muchas operaciones potentes que Jinja admite en los archivos de plantilla. Por ejemplo, las plantillas también admiten instrucciones de control, que se encuentran dentro {% ... %}de bloques. La siguiente versión de la plantilla index.html añade una instrucción condicional:
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Microblog</title>
{% else %}
<title>Welcome to Microblog!</title>
{% endif %}
</head>
<body>
<h1>Hello, {{ user.username }}!</h1>
</body>
</html>Bucles
Hasta este punto, la plantilla index.html mostraba únicamente información estática o variables individuales, como el nombre del usuario conectado. Sin embargo, en una aplicación real es habitual trabajar con colecciones de datos, por ejemplo:
- Publicaciones de un blog.
- Comentarios.
- Productos.
- Resultados de consultas.
- Registros de una base de datos.
Para representar este tipo de estructuras, Jinja2 incorpora instrucciones de control similares a las de Python, entre ellas el bucle for.
En app/routes.py, debajo del usuario autenticado, crea una lista llamada posts. Cada elemento de la lista es un diccionario que representa una publicación con autor:body . A la función añade posts=posts
posts = [
{
'author': {'username': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'username': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]Uso del bucle for en Jinja2
En templates/index.html, la colección se recorre mediante la instrucción:
{% for post in posts %}
...
{% endfor %}Durante cada iteración, post representa un elemento individual de la lista al que se puede acceder a sus atributos o claves.
Acceso a estructuras anidadas
Jinja2 permite navegar por diccionarios anidados usando la notación de punto, lo que hace el código más legible.
{{ post.author.username }}
{{ post.body }}Herencia de plantillas en Jinja2
La idea consiste en crear una plantilla base que contenga toda la estructura común del sitio y dejar definidos ciertos espacios vacíos, llamados bloques, donde cada página insertará su contenido específico.
La plantilla base
La plantilla base.html define la estructura general de todas las páginas.
El bloque content
La instrucción define una zona reemplazable. La plantilla hija podrá proporcionar el contenido que se insertará exactamente en ese punto.
{% block content %}{% endblock %}Plantilla hija: index.html
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{ user.username }}!</h1>
{% for post in posts %}
<div>
<p>
{{ post.author.username }} says:
<b>{{ post.body }}</b>
</p>
</div>
{% endfor %}
{% endblock %}La instrucción extends Indica que index.html no es un documento HTML completo, sino una plantilla que hereda de base.html.
{% extends "base.html" %}Cuando Flask ejecuta: render_template("index.html"), Jinja2 realiza internamente estos pasos:
- Carga
index.html. - Detecta
{% extends "base.html" %}. - Carga
base.html. - Sustituye el bloque
contentdebase.htmlpor el bloquecontentdefinido enindex.html. - Genera el HTML final.