应用工厂

如果你已经在你的应用中使用包和蓝图 (使用蓝图的模块化应用),那么还有一些非常好的方法可以进一步改善体验。一个常见的模式是在导入蓝图时创建应用对象。但是,如果你将创建此对象的操作移到一个函数中,那么稍后你可以创建此应用的多个实例。

那么你为什么要这样做呢?

  1. 测试。你可以拥有具有不同设置的应用实例来测试每种情况。

  2. 多实例。想象一下,你想运行同一应用的多个版本。当然,你可以在你的网络服务器中设置具有不同配置的多个实例,但是如果你使用工厂,你可以在同一应用进程中运行同一应用的多个实例,这可能很方便。

那么你实际上会如何实现它呢?

基本工厂

想法是在一个函数中设置应用。像这样

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    from yourapplication.model import db
    db.init_app(app)

    from yourapplication.views.admin import admin
    from yourapplication.views.frontend import frontend
    app.register_blueprint(admin)
    app.register_blueprint(frontend)

    return app

缺点是你不能在导入时在蓝图中使用应用对象。但是,你可以在请求中从内部使用它。你如何访问带有配置的应用?使用 current_app

from flask import current_app, Blueprint, render_template
admin = Blueprint('admin', __name__, url_prefix='/admin')

@admin.route('/')
def index():
    return render_template(current_app.config['INDEX_TEMPLATE'])

在这里,我们在配置中查找模板的名称。

工厂 & 扩展

最好创建你的扩展和应用工厂,以便扩展对象最初不会绑定到应用。

Flask-SQLAlchemy 为例,你不应该这样做

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    db = SQLAlchemy(app)

而是,在 model.py (或等效文件) 中

db = SQLAlchemy()

以及在你的 application.py (或等效文件) 中

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    from yourapplication.model import db
    db.init_app(app)

使用这种设计模式,没有应用特定的状态存储在扩展对象上,因此一个扩展对象可以用于多个应用。有关扩展设计的更多信息,请参阅 Flask 扩展开发

使用应用

要运行这样的应用,你可以使用 flask 命令

$ flask --app hello run

Flask 将自动检测工厂,如果它在 hello 中被命名为 create_appmake_app。你也可以像这样将参数传递给工厂

$ flask --app hello:create_app(local_auth=True) run

然后在 myapp 中的 create_app 工厂被调用,并带有关键字参数 local_auth=True。有关更多详细信息,请参阅 命令行界面

工厂改进

上面的工厂函数不是很智能,但是你可以改进它。以下更改很容易实现

  1. 使其可以为单元测试传入配置值,这样你就不必在文件系统上创建配置文件。

  2. 在应用设置时从蓝图调用一个函数,这样你就有了一个地方来修改应用的属性 (例如,挂钩在请求处理程序之前/之后等)。

  3. 在必要时,在创建应用时添加 WSGI 中间件。