アプリケーション製造工場(Application Factories) Application Factories

もしパッケージとblueprintをアプリケーションで既に使っている場合(Blueprintを使ったアプリケーションのモジュール化参照)、さらによい経験へ改善させるとてもよい方法がいくつかあります。よくあるパターンでは、blueprintがimportされたときにアプリケーションのオブジェクトを作成します。しかし、もしこのオブジェクト作成を関数の内側に移動させれば、あとでこのアプリのインスタンスを複数作成できるようになります。 If you are already using packages and blueprints for your application (:ref:`blueprints`) there are a couple of really nice ways to further improve the experience. A common pattern is creating the application object when the blueprint is imported. But if you move the creation of this object into a function, you can then create multiple instances of this app later.

では、なぜそれをしたいのでしょうか? So why would you want to do this?

  1. テスト。各ケースのために違う設定を使ったアプリケーションのインスタンスを持つことが可能です。 Testing. You can have instances of the application with different settings to test every case.

  2. 複数インスタンス。同じアプリケーションの違うバージョンを実行したいと想像してください。自分のwebサーバに違う設定をセットアップした複数のインスタンスを持つことも、もちろん可能ですが、しかしもしfactoryを使うと、同じアプリケーションのプロセスで走っている同じアプリケーションの複数のインスタンスを持つことができ、便利です。 Multiple instances. Imagine you want to run different versions of the same application. Of course you could have multiple instances with different configs set up in your webserver, but if you use factories, you can have multiple instances of the same application running in the same application process which can be handy.

では、どうやって実際にそれを実装するのでしょうか? So how would you then actually implement that?

基本的なFactory(Basic Factories) Basic Factories

関数の中でアプリケーションをセットアップするというアイデアです。このようになります: The idea is to set up the application in a function. Like this::

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

マイナス面は、blueprintの中でのimport時にはアプリケーションを使えないことです。しかし、リクエストの中ではblueprintからアプリケーションを使うことができます。どうやって設定されたアプリケーションにアクセスするのでしょうか?current_appを使います: The downside is that you cannot use the application object in the blueprints at import time. You can however use it from within a request. How do you get access to the application with the config? Use :data:`~flask.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'])

上の例では、テンプレートの名前をconfigから探しています。 Here we look up the name of a template in the config.

FactoryとFlask拡張(Factories & Extensions) Factories & Extensions

Flask拡張のオブジェクトが最初からアプリケーションに結び付けられないために、好ましいのは自分のFlask拡張(のオブジェクト)とapp factoryを(別々に)作成することです。 It's preferable to create your extensions and app factories so that the extension object does not initially get bound to the application.

例えばFlask-SQLAlchemyを使うとき、以下のようなコードを使って何かをするべきではありません: Using `Flask-SQLAlchemy <https://flask-sqlalchemy.palletsprojects.com/>`_, as an example, you should not do something along those lines::

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

    db = SQLAlchemy(app)

しかし、むしろ、以下の内容はmodel.py(もしくは同等のもの)の中にし: But, rather, in model.py (or equivalent)::

db = SQLAlchemy()

そしてapplication.py(もしくは同等のもの)は以下のようにします: and in your application.py (or equivalent)::

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拡張オブジェクトを複数のappで使用できます。Flask拡張の設計に関するさらなる情報は、Flask拡張の開発を確認してください。 Using this design pattern, no application-specific state is stored on the extension object, so one extension object can be used for multiple apps. For more information about the design of extensions refer to :doc:`/extensiondev`.

アプリケーションの使用 Using Applications

このようなアプリケーションを実行するために、flaskコマンドを使用できます。 To run such an application, you can use the :command:`flask` command::

$ export FLASK_APP=myapp
$ flask run

Flaskは自動的にfactory(create_appまたはmake_app)をmyappの中から見つけ出します。以下のように、factoryへ引数を渡すことも可能です: Flask will automatically detect the factory (``create_app`` or ``make_app``) in ``myapp``. You can also pass arguments to the factory like this::

$ export FLASK_APP="myapp:create_app('dev')"
$ flask run

こうすると、myappの中のcreate_app factoryが'dev'文字列を引数に使って呼び出されます。さらなる詳細はコマンドライン・インタフェースを確認してください。 Then the ``create_app`` factory in ``myapp`` is called with the string ``'dev'`` as the argument. See :doc:`/cli` for more detail.

Factoryの改善(Factory Improvements) Factory Improvements

上記のfactory関数は非常に賢いものではありませんが、改善可能です。実装しやすいものは以下の変更です: The factory function above is not very clever, but you can improve it. The following changes are straightforward to implement:

  1. ユニットテストから設定値を投入可能にし、ファイルシステム上に(ユニットテスト用の)設定ファイルを作成せずに済むようにします。 Make it possible to pass in configuration values for unit tests so that you don't have to create config files on the filesystem.

  2. (リクエスト処理のbefore/afterフックのように)アプリケーションの属性を変更する場所を持てるように、アプリケーションを設定するときblueprintから関数を呼び出します。 Call a function from a blueprint when the application is setting up so that you have a place to modify attributes of the application (like hooking in before/after request handlers etc.)

  3. 必要に応じて、アプリケーションが作成されるときWSGIミドルウェアの中に追加します。 Add in WSGI middlewares when the application is being created if necessary.