应用工厂¶

如果你已经在应用中使用了包和蓝图( 使用蓝图的模块化应用 ),那么还有许多方法可以更进一步地改进你的应用。常用的方案是导入蓝图后创建应用对象,但是如果在一个函数中创建对象,那么就可以创建多个实例。

那么这样做有什么用呢?

  • 用于测试。可以针对不同的情况使用不同的配置来测试应用。
  • 用于多实例,如果你需要运行同一个应用的不同版本的话。当然你可以在服务器上使用不同配置运行多个相同应用,但是如果使用应用工厂,那么你可以只使用一个应用进程而得到多个应用实例,这样更容易操控。
    那么如何做呢?

基础工厂¶

方法是在一个函数中设置应用,具体如下:

  1. def create_app(config_filename):
  2. app = Flask(__name__)
  3. app.config.from_pyfile(config_filename)
  4.  
  5. from yourapplication.model import db
  6. db.init_app(app)
  7.  
  8. from yourapplication.views.admin import admin
  9. from yourapplication.views.frontend import frontend
  10. app.register_blueprint(admin)
  11. app.register_blueprint(frontend)
  12.  
  13. return app

这个方法的缺点是在导入时无法在蓝图中使用应用对象。但是你可以在一个请求中使用它。如何通过配置来访问应用?使用 current_app:

  1. from flask import current_app, Blueprint, render_template
  2. admin = Blueprint('admin', __name__, url_prefix='/admin')
  3.  
  4. @admin.route('/')
  5. def index():
  6. return render_template(current_app.config['INDEX_TEMPLATE'])

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

工厂与扩展¶

最好分别创建扩展和应用工厂,这样扩展对象就不会过早绑定到应用。

以使用 Flask-SQLAlchemy 为例,不应当这样:

  1. def create_app(config_filename):
  2. app = Flask(__name__)
  3. app.config.from_pyfile(config_filename)
  4.  
  5. db = SQLAlchemy(app)

而是在 model.py (或其他等价文件)中:

  1. db = SQLAlchemy()

在 application.py (或其他等价文件)中:

  1. def create_app(config_filename):
  2. app = Flask(__name__)
  3. app.config.from_pyfile(config_filename)
  4.  
  5. from yourapplication.model import db
  6. db.init_app(app)

使用这个设计方案,不会有应用特定状态储存在扩展对象上,因此扩展对象就可以被多个应用使用。更多关于扩展设计的信息参见 Flask 扩展开发

使用应用¶

使用 flask 命令运行工厂应用:

  1. export FLASK_APP=myapp
  2. flask run

Flask 会自动在 myapp 中探测工厂( create_app 或者 make_app )。还可这样向工厂传递参数:

  1. export FLASK_APP="myapp:create_app('dev')"
  2. flask run

这样, myapp 中的 create_app 工厂就会使用'dev' 作为参数。更多细节参见 命令行接口

改进工厂¶

上面的工厂函数还不是足够好,可以改进的地方主要有以下几点:

  • 为了单元测试,要想办法传入配置,这样就不必在文件系统中创建配置文件。
  • 当设置应用时从蓝图调用一个函数,这样就可以有机会修改属性(如挂接请求前/后处理器等)。
  • 如果有必要的话,当创建一个应用时增加一个 WSGI 中间件。

原文: https://dormousehole.readthedocs.io/en/latest/patterns/appfactories.html