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.

Flask Blueprint 蓝图模块架构


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

# Ruta del archivo: auth.py (Blueprint de autenticación de usuario)
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

# Ruta del archivo: blog.py (Blueprint de blog)
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

# Ruta del archivo: app.py
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

# Dentro de auth.py, es más conciso usar referencias relativas
@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

# Crear un Blueprint con una carpeta de plantillas independiente
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

# Ruta del archivo: app.py
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

@bp.before_request
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

Los 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。

Otras extensiones