应用程序工厂

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

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

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

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

那么,你将如何实际实现呢?

基本工厂

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

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

如果在 hello 中将工厂命名为 create_appmake_app,Flask 将自动检测到该工厂。您还可以像这样向工厂传递参数

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

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

工厂改进

上面的工厂函数不是很巧妙,但您可以对其进行改进。以下更改易于实现

  1. 使其能够传递单元测试的配置值,以便您不必在文件系统上创建配置文件。

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

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