说明
建立这个init.py文件有两点原因
◇:
它包含一个应用工厂函数,create_app(), 加载数据库配置,路由策略设置等,返回一个拥有这些属性的Flask实例。
◇:
它是一个包,当项目启动时会自动运行文件中的代码。app = Flask(name, instance_relative_config=True)
◇:
name是模块名,实例需要知道这个应用的位置在哪,set FLASK_APP=flaskr
中的flaskr就是这个name
◇:
instance_relative_config=True,表明配置文件跟这个实例目录是有关系的app.config.from_mapping(), 为Flask实例关联数据库文件位置,以及保证数据安全
◇:
SECRET_KEY用于保证数据安全
◇:
DATABASE,SQLite的数据库文件保存的位置,即项目目录下的instance/flaskr.sqlite
app.config.from_pyfile() 如果config.py文件存在,则采用此配置文件。后期项目增加,如需要用到redis、elasticsearch、图片和文档上传路径时, 就需要讲这些配置信息与数据库配置,一并写入到config.py中,方便管理。
- db.init_app(app),分离扩展的实例化和初始化操作。
源代码如下
register_blueprint(auth.bp) 将蓝图注册到Flask实例中。auth文件中有一条: bp=Blueprint('auth', name, url_prefix='/auth'), 蓝图组织视图极其代码的一种方式,提供模块化管理程序路由的功能。
◇:
创建一个名为auth
的Blueprint
◇:
name表明这个Blueprint在哪里定义它
◇:
url_prefix='/auth' 表明所有使用bp.route()的URL前面都加一个authapp.add_url_rule("/", endpoint='index') 主页的默认页面为
index.html
源代码如下:
import os
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY="dev",
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite')
)
if test_config is None:
# Load the instance config, if it exists, when not testing
app.config.from_pyfile("config.py", silent=True)
else:
# Load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.mkdir(app.instance_path)
except OSError:
pass
from . import db
db.init_app(app)
from . import auth
app.register_blueprint(auth.bp)
from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule("/", endpoint='index')
return app
总结
create_app()是一个工厂函数,是指创建其他对象的对象,本例是创建Flask程序实例,并返回实例APP。只不过在返回前为这个程序实例加载了一些配置,如数据库相关配置、注册了蓝图。最后,APP是具有这些属性的程序实例。
工厂函数的好处有一下几点:
- 方便测试与部署, 不用将加载的配置写死在某处,可在不同的地方按需配置创建程序实例。
- 创建扩展对象的操作可以分离到单独的模块,这样可以有效减少循环依赖的发生。
- 分离扩展的初始化操作。
工厂函数一般在程序包的构造文件中创建,如果你愿意,也可以在程序包内新建的模块来存放,比如factory.py或是app.py。
关于分离扩展的实例化, 这样做的原因是,为了完成扩展的初始化操作,需要实例化扩展类时倒入程序实例。但是使用工厂函数时,并没有一个创建好的程序实例(只有return app, app没有run起来)。如果将初始化操作放在工厂函数中,就没有一个全局的扩展对象可以使用(作用域在create_app中), 比如表示数据库操作的db对象。
为了解决这个问题,就采用init_app()函数来分离扩展的实例化和初始化操作。此项目中关于DB的初始化(建表操作)就放在了db.py文件中。