应用工厂

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

你为什么要这么做?

  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

如果命名为FASK,FASK将自动检测工厂 create_appmake_app 在……里面 hello 。您还可以将参数传递给工厂,如下所示:

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

然后是 create_app 工厂在 myapp 使用关键字参数调用 local_auth=True 。看见 命令行界面 了解更多详细信息。

工厂改进

上面的工厂功能不是很聪明,但是你可以改进它。以下更改易于实现:

  1. 使传递单元测试的配置值成为可能,这样就不必在文件系统上创建配置文件。

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

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