2010-05-27 23:55:57 +08:00
|
|
|
Application Factories
|
|
|
|
|
=====================
|
|
|
|
|
|
2011-06-18 02:27:25 +08:00
|
|
|
If you are already using packages and blueprints for your application
|
2020-04-05 03:57:14 +08:00
|
|
|
(:doc:`/blueprints`) there are a couple of really nice ways to further improve
|
2010-05-27 23:55:57 +08:00
|
|
|
the experience. A common pattern is creating the application object when
|
2016-12-19 21:37:34 +08:00
|
|
|
the blueprint is imported. But if you move the creation of this object
|
2015-12-03 17:51:24 +08:00
|
|
|
into a function, you can then create multiple instances of this app later.
|
2010-05-27 23:55:57 +08:00
|
|
|
|
|
|
|
|
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. 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?
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2013-03-16 18:13:07 +08:00
|
|
|
from yourapplication.model import db
|
|
|
|
|
db.init_app(app)
|
|
|
|
|
|
2010-05-27 23:55:57 +08:00
|
|
|
from yourapplication.views.admin import admin
|
|
|
|
|
from yourapplication.views.frontend import frontend
|
2011-06-18 03:58:03 +08:00
|
|
|
app.register_blueprint(admin)
|
|
|
|
|
app.register_blueprint(frontend)
|
2010-05-27 23:55:57 +08:00
|
|
|
|
|
|
|
|
return app
|
|
|
|
|
|
2011-06-18 03:58:03 +08:00
|
|
|
The downside is that you cannot use the application object in the blueprints
|
2010-05-27 23:55:57 +08:00
|
|
|
at import time. You can however use it from within a request. How do you
|
2011-06-16 22:28:51 +08:00
|
|
|
get access to the application with the config? Use
|
2010-05-27 23:55:57 +08:00
|
|
|
:data:`~flask.current_app`::
|
|
|
|
|
|
2011-06-18 03:58:03 +08:00
|
|
|
from flask import current_app, Blueprint, render_template
|
|
|
|
|
admin = Blueprint('admin', __name__, url_prefix='/admin')
|
2010-05-27 23:55:57 +08:00
|
|
|
|
|
|
|
|
@admin.route('/')
|
|
|
|
|
def index():
|
|
|
|
|
return render_template(current_app.config['INDEX_TEMPLATE'])
|
|
|
|
|
|
|
|
|
|
Here we look up the name of a template in the config.
|
|
|
|
|
|
2013-10-11 20:39:46 +08:00
|
|
|
Factories & Extensions
|
|
|
|
|
----------------------
|
2013-03-16 18:13:07 +08:00
|
|
|
|
2013-10-11 20:39:46 +08:00
|
|
|
It's preferable to create your extensions and app factories so that the
|
|
|
|
|
extension object does not initially get bound to the application.
|
|
|
|
|
|
2019-06-24 06:37:51 +08:00
|
|
|
Using `Flask-SQLAlchemy <https://flask-sqlalchemy.palletsprojects.com/>`_,
|
2014-02-09 21:35:38 +08:00
|
|
|
as an example, you should not do something along those lines::
|
2014-11-05 11:45:22 +08:00
|
|
|
|
2013-10-11 20:39:46 +08:00
|
|
|
def create_app(config_filename):
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
app.config.from_pyfile(config_filename)
|
|
|
|
|
|
|
|
|
|
db = SQLAlchemy(app)
|
|
|
|
|
|
|
|
|
|
But, rather, in model.py (or equivalent)::
|
2013-03-16 18:13:07 +08:00
|
|
|
|
|
|
|
|
db = SQLAlchemy()
|
2014-11-05 11:45:22 +08:00
|
|
|
|
2013-10-11 20:39:46 +08:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
Using this design pattern, no application-specific state is stored on the
|
2014-11-05 11:45:22 +08:00
|
|
|
extension object, so one extension object can be used for multiple apps.
|
2013-10-11 20:39:46 +08:00
|
|
|
For more information about the design of extensions refer to :doc:`/extensiondev`.
|
2013-03-16 18:13:07 +08:00
|
|
|
|
2010-05-27 23:55:57 +08:00
|
|
|
Using Applications
|
|
|
|
|
------------------
|
|
|
|
|
|
2020-10-16 05:08:37 +08:00
|
|
|
To run such an application, you can use the :command:`flask` command:
|
2010-05-27 23:55:57 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
.. code-block:: text
|
2020-10-16 05:08:37 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
$ flask run --app hello run
|
2020-10-16 05:08:37 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
Flask will automatically detect the factory if it is named
|
|
|
|
|
``create_app`` or ``make_app`` in ``hello``. You can also pass arguments
|
|
|
|
|
to the factory like this:
|
2020-10-16 05:08:37 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
.. code-block:: text
|
2020-10-16 05:08:37 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
$ flask run --app hello:create_app(local_auth=True)``
|
2022-01-11 20:59:08 +08:00
|
|
|
|
2022-06-18 00:26:26 +08:00
|
|
|
Then the ``create_app`` factory in ``myapp`` is called with the keyword
|
|
|
|
|
argument ``local_auth=True``. See :doc:`/cli` for more detail.
|
2010-05-27 23:55:57 +08:00
|
|
|
|
|
|
|
|
Factory Improvements
|
|
|
|
|
--------------------
|
|
|
|
|
|
2017-10-20 03:32:47 +08:00
|
|
|
The factory function above is not very clever, but you can improve it.
|
|
|
|
|
The following changes are straightforward to implement:
|
2010-05-27 23:55:57 +08:00
|
|
|
|
2017-10-20 03:32:47 +08:00
|
|
|
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. Call a function from a blueprint when the application is setting up so
|
2010-05-27 23:55:57 +08:00
|
|
|
that you have a place to modify attributes of the application (like
|
2017-10-20 03:32:47 +08:00
|
|
|
hooking in before/after request handlers etc.)
|
|
|
|
|
3. Add in WSGI middlewares when the application is being created if necessary.
|