Flask: 应用工厂中蓝图必要吗?
我想要创建几个应用工厂(现在有一个用于开发,另一个用于测试)。我在想,怎么做才是正确的方式。
目前我使用应用对象来注册视图(通过 @app.route()
装饰器)。我需要开始使用蓝图(而不是应用对象)来注册视图吗?有没有办法在不使用蓝图的情况下,正确地创建应用工厂?
3 个回答
你当然可以没有蓝图就创建应用工厂,但这样通常没有意义。
假设你有一个叫做 myapp
的应用包。这里是你的 __init__.py
文件:
from flask import Flask
def create_app():
app = Flask(__name__)
return app
现在我们在 myapp
包外面创建一个新的 .py
文件,叫做 autoapp.py
(或者 wsgi.py
、manage.py
等等)。在 autoapp.py
文件中,你会创建应用实例,并从 myapp
中导入视图:
from myapp import create_app
app = create_app()
from myapp import views
这个导入语句会把 app
和你的路由连接起来。你可以在 views.py
中这样导入 app
:
from autoapp import app
@app.route('/')
def index():
return 'Hello!'
应用的结构:
myapp/
myapp/
__init__.py
views.py
autoapp.py
对于那些在网上搜索这个问题的人,你不一定要使用蓝图。只需在你的 routes.py(或者 views.py,随便哪个)中导入 current_app 作为 app,就可以开始了。
from flask import current_app as app
另外,你还需要在工厂函数(create_app 函数)中添加这些内容,以注册你的路由:
with app.app_context():
from . import routes
从技术上讲,你其实不需要蓝图(blueprints),可以直接在你的 create_app
函数里注册每一个路由。不过,通常这样做并不是个好主意,这也是蓝图存在的原因。
没有蓝图的例子
def create_app():
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
return app
如果你配置得当,可以有一个单一的应用工厂,既可以用于测试,也可以用于其他用途。如果你想根据是否在测试中加载不同的蓝图,可以这样做。
from project.config import configurations as c
def create_app(config=None):
" make the app "
app = Flask(__name__)
app.config.from_object(c.get(config, None) or c['default'])
configure_blueprints(app)
return app
def configure_blueprints(app):
" register the blueprints on your app "
if app.testing:
from project.test_bp import bp
app.register_blueprint(bp)
else:
from project.not_test_bp import bp
app.register_blueprint(bp)
然后 project/config.py
可以像这样:
class DefaultConfig(object):
PROJECT_NAME = 'my project'
class TestingConfig(DefaultConfig):
TESTING = True
class DevConfig(DefaultConfig):
DEBUG = True
configurations = {
'testing': TestingConfig,
'dev': DevConfig,
'default': DefaultConfig
}
为每个蓝图创建一个文件夹,文件夹里的 __init__.py
文件用来实例化这个蓝图。假设有一个叫 routes
的蓝图。
from flask import Blueprint
bp = Blueprint('routes', __name__)
from project.routes import views
那么在 project/routes/views.py
中,你可以放置你的视图。
from project.routes import bp
@bp.route('/')
def index():
return render_template('routes/index.html')