Blueprint (Blueprint)
Cuando la aplicación tiene un solo archivo, escribir todas las rutas juntas no es un problema.
Pero a medida que crecen las funcionalidades (módulo de usuarios, módulo de artículos, panel de administración), el código se vuelve difícil de mantener.
Blueprintes la solución modular que ofrece Flask, que te permite dividir la aplicación en unidades funcionales independientes.
¿Por qué se necesitan Blueprints?
Los problemas centrales que resuelven los Blueprints:
- Organización del código: agrupa rutas, plantillas y archivos estáticos relacionados.
- Reutilización: el mismo Blueprint puede registrarse en diferentes aplicaciones, o registrarse varias veces (con diferentes prefijos).
- Colaboración en equipo: diferentes desarrolladores se encargan de diferentes módulos de Blueprint, reduciendo conflictos.
Crear Blueprints
Los Blueprints se creanBlueprintcon la clase, y su usoFlaskes muy similar: los mismos decoradores de ruta, la misma forma de escribir funciones de vista.
Ejemplo
from flask import Blueprint, render_template, request, session, redirect, url_for
# Crear la instancia del Blueprint
# El primer parámetro "auth" es el nombre del Blueprint (se usa para referenciar en url_for)
# __name__ le dice al Blueprint dónde buscar plantillas y archivos estáticos
bp = Blueprint("auth", __name__)
# En el Blueprint se usa bp.route, no app.route
@bp.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get("username", "")
if username:
session["username"] = username
return redirect(url_for("blog.index"))
return render_template("auth/login.html")
@bp.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
username = request.form.get("username", "")
if username:
return redirect(url_for("auth.login"))
return render_template("auth/register.html")
@bp.route("/logout")
def logout():
session.clear()
return redirect(url_for("blog.index"))
Ejemplo
from flask import Blueprint, render_template
bp = Blueprint("blog", __name__)
@bp.route("/")
def index():
# Datos simulados de artículos
posts = [
{"title": Introducción a Flask, "author": "ejemplo"},
{"title": Explicación detallada de Blueprint, "author": "EJEMPLO"},
]
return render_template("blog/index.html", posts=posts)
@bp.route("/create", methods=["GET", "POST"])
def create():
return render_template("blog/create.html")
Registrar Blueprints
Los Blueprints creados no se activan automáticamente; es necesario registrarlos en la aplicación:
Ejemplo
from flask import Flask
from auth import bp as auth_bp
from blog import bp as blog_bp
app = Flask(__name__)
app.secret_key = "dev-secret-key"
# Registrar los Blueprints en la aplicación
# url_prefix: agrega un prefijo común a todas las rutas del Blueprint
app.register_blueprint(auth_bp, url_prefix="/auth")
# Las rutas del Blueprint auth pasan a ser: /auth/login, /auth/logout, /auth/register
app.register_blueprint(blog_bp)
# El Blueprint blog no tiene prefijo, sus rutas se mantienen: /, /create
Tabla de rutas completa después del registro:
| URL | Blueprint | endpoint (para usar con url_for) |
|---|---|---|
| / | blog | blog.index |
| /create | blog | blog.create |
| /auth/login | auth | auth.login |
| /auth/register | auth | auth.register |
| /auth/logout | auth | auth.logout |
Después de registrar el Blueprint,url_for()el endpoint debe llevar el prefijo del nombre del Blueprint, por ejemplourl_for("auth.login")en lugar deurl_for("login")。
Uso especial de url_for en Blueprints
Dentro del mismo Blueprint, se pueden usar referencias relativas que comienzan con un punto:
Ejemplo
@bp.route("/")
def index():
# Referencias relativas dentro del mismo Blueprint (comienzan con .)
login_url = url_for(".login") # Equivale a url_for("auth.login")
register_url = url_for(".register") # Equivale a url_for("auth.register")
# Las referencias entre Blueprints requieren el endpoint completo
blog_url = url_for("blog.index") # Referencia al index del Blueprint blog
Plantillas y archivos estáticos de Blueprints
Los Blueprints también pueden tener sus propias plantillas y archivos estáticos.
Cuando el Blueprint tiene su propia carpeta de plantillas, Flask primero buscará en latemplatescarpeta de plantillas de la aplicación; si no la encuentra, buscará en la carpeta especificada por el Blueprint.
Ejemplo
bp = Blueprint("auth", __name__, template_folder="templates")
# Organización particular de plantillas del Blueprint
# Ruta: auth/templates/auth/login.html
# Al renderizar: render_template("auth/login.html")
# Esta organización evita conflictos de nombres de archivo (login.html puede ser diferente en auth y blog)
Estructura de directorios recomendada para Blueprints:
myflaskapp/
├── app.py # 应用入口,注册蓝图
├── auth.py # 认证蓝图
├── blog.py # 博客蓝图
├── templates/ # 应用级模板(公共 base.html 等)
│ └── base.html
├── static/ # 应用级静态文件
│ └── style.css
├── auth/ # auth 蓝图的独立资源(可选)
│ └── templates/
│ └── auth/
│ ├── login.html
│ └── register.html
└── blog/ # blog 蓝图的独立资源(可选)
└── templates/
└── blog/
├── index.html
└── create.html
La forma más simple es no configurar una carpeta de plantillas separada para el Blueprint, y poner las plantillas en el directorio raíz del proyecto, en latemplates/carpeta templates, usando subdirectorios para distinguirlas.templates/auth/login.html、templates/blog/index.html。
Patrón de fábrica — create_app
A medida que aumentan los Blueprints, crear directamente en el nivel superior del móduloapp = Flask(__name__)se encontrará con problemas de importación circular.
El patrón de fábrica (Factory Pattern) es la mejor práctica para resolver este problema:
Ejemplo
from flask import Flask
def create_app():
"""Función fábrica de la aplicación: devuelve una instancia de Flask configurada"""
app = Flask(__name__)
app.secret_key = "dev-secret-key"
# Cargar configuración
app.config.from_pyfile("config.py", silent=True)
# Importar los Blueprints dentro de la función para evitar importaciones circulares
from auth import bp as auth_bp
from blog import bp as blog_bp
# Registrar Blueprints
app.register_blueprint(auth_bp, url_prefix="/auth")
app.register_blueprint(blog_bp)
return app
Ventajas del patrón de fábrica:
- Elimina las importaciones circulares: los Blueprints pueden importarapp,appy también ser importados, porque la importación ocurre dentro de la función.
- Facilita las pruebas: se pueden crear instancias de app con diferentes configuraciones para realizar pruebas.
- Despliegue de múltiples instancias: el mismo código puede crear múltiples instancias de app independientes.
Después de usar el patrón de fábrica, se necesitaflask --app "app:create_app()" runiniciar:
$ flask --app "app:create_app()" run
Otras funciones de Blueprints
Los Blueprints también admiten decoradores como before_request, errorhandler, etc., con el mismo uso que app:
Ejemplo
def check_login():
"""Verificar el estado de inicio de sesión antes de todas las solicitudes del Blueprint auth"""
if request.endpoint not in ("auth.login", "auth.register"):
if "username" not in session:
return redirect(url_for("auth.login"))
@bp.errorhandler(404)
def not_found(error):
"""Página de error 404 exclusiva del Blueprint auth"""
return render_template("auth/404.html"), 404
Otras extensionesLos decoradores del Blueprintbefore_requestsolo afectan las rutas dentro de ese Blueprint. Si necesitas ejecutar lógica antes de todas las solicitudes, deberías usarapp.before_request。