解释1:
允许将应用组织为模块,每个模块有自洽的 MVC,开发者做些工作可以使模块间依赖尽可能少,必要时可以按 blueprint 为单位做垂直拆分。
依赖反转,允许把 route 挂到 blueprint 对象而非全局 app 对象上。
解释2:
1 概述
蓝图/Blueprint是Flask应用程序组件化的方法,可以在一个应用内或跨越 多个项目共用蓝图。使用蓝图可以极大地简化大型应用的开发难度,也为Flask扩展 提供了一种在应用中注册服务的集中式机制。
2 初识蓝图
蓝图/Blueprint对象用起来和一个应用/Flask对象差不多,最大的区别在于一个 蓝图对象没有办法独立运行,必须将它注册到一个应用对象上才能生效。
使用蓝图可以分为三个步骤
1.创建一个蓝图对象
ezbp =Blueprint("ezbp",__name__)
2.在这个蓝图对象上进行操作,入注册路由、指定静态文件夹、注册模板过滤器...
@ezbp.route('/')defezbp_index():return'Welcome to my blueprint'
3.在应用对象上注册这个蓝图对象
app.register_blueprint(ezbp,url_prefix='/ezbp')
当这个应用启动后,通过/ezbp/可以访问到蓝图中定义的视图函数。
考察上面的代码,可以看到在蓝图对象上注册路由的方法和在应用对象上完全 一样,那么,值得思考的是,蓝图和应用对象的运行机制是一样的吗?
example:
#-*- coding:utf-8 -*-fromflaskimportFlask,Blueprintapp= Flask(__name__)
@app.route('/')defapp_index():return'go blueprint'ezbp = Blueprint("ezbp",__name__)
@ezbp.route('/')defezbp_index():return'Welcome to my blueprint'app.register_blueprint(ezbp,url_prefix='/ezbp')
app.run(host='0.0.0.0',port=80)
ouptut:
3 运行机制———说白了就是会自动补充URL前缀,并且能使用相同的视图函数
蓝图并不是一个可插拔的应用 —— 它只是保存了一组将来可以在应用对象上执行 的操作—— 注册路由就是一种操作。
当在应用对象上调用route 装饰器或使用add_url_rule()方法注册路由时, 我们已经知道,这个操作将修改应用对象的两张路由表:url_map和view_functions; 然而,蓝图对象根本就没有路由表,当我们在蓝图对象上调用route装饰器或使用 add_url_rule()方法注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一项:下图为blueprint和FLask route的对比
lambad s: s.add_url_rule('/',view_func=ezbp_index)定义了一个匿名函数, 参数s就是将来被传入的应用对象。当执行应用对象的register_blueprint()方法时,应用对象将从蓝图对象的defered_functions列表中取出每一项,并以自身 作为参数执行该匿名函数 —— 即调用应用对象的add_url_rule()方法,这将真正的 修改应用对象的两张路由表。
所以说,蓝图这个名字起得的确恰当,蓝图的那些方法仅仅记录了未来应该发生的操作, 而不是当即实现。
2 蓝图的URL前缀
继续使用前一节的图,注意其中被橘黄色荧光笔涂抹的代码:
当我们在应用对象上注册一个蓝图时,需要指定一个url_prefix关键字 参数(这个参数默认是/)。在上面的图中可以看到,在应用最终的路由表url_map中,在蓝图上注册的路由URL自动被加上了这个前缀。
这相当有用,我们可以在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在 注册蓝图时将不同的蓝图挂接到不同的自路径即可 —— 想一想对于大型应用而言,不同 的蓝图通常是不同的人员开发的,你很难保证URL规则不发生冲突!
example:
#-*- coding:utf-8 -*-fromflaskimportFlask,Blueprint
shop= Blueprint('shop','shop')
@shop.route('/')defv_index():return'shop root'vip= Blueprint('vip','vip')
@vip.route('/')defv_index():return'vip homepage'admin= Blueprint('admin','admin')
@admin.route('/')defv_index():return'admin root'app= Flask(__name__)
app.register_blueprint(shop,url_prefix='/')
app.register_blueprint(admin,url_prefix='/admin')
app.register_blueprint(vip,url_prefix='/vip')
app.run(host='0.0.0.0',port=80)
output:
4 蓝图的endpoint———加上蓝图前缀
图继续,这次关注绿色荧光笔涂抹的代码:
我们创建蓝图对象时,第一个参数指定了蓝图的名字。当在应用中注册蓝图时, 蓝图的路由项中的访问点endpoint被自动添加了这个名字。
这有什么用?这涉及到url_for()的正确工作与否。
当不同的团队开发不同的蓝图时,和URL规则类似,你很难保证他们的视图函数名 彼此不同,尤其像index这样俗套的名字。如果不对来自不同蓝图的endpoint 进行区隔,那么url_for('index')到底应该生成那个URL?这显然无法确定。
一旦给不同蓝图的endpoint加上了蓝图名前缀,我们可以确切地告诉url_for() 了:
url_for('shop.v_index')#/shop/url_for('admin.v_index')#/admin/
example:
#-*- coding:utf-8 -*-fromflaskimportFlask,Blueprint,url_for,render_template_string
shop= Blueprint('shop',__name__)
@shop.route('/')defv_index():return'''
@admin.route('/')defv_index():return'''
app.register_blueprint(shop,url_prefix='/shop')
app.register_blueprint(admin,url_prefix='/admin')
@app.route('/')defv_index():
tpl='''
'''returnrender_template_string(tpl)
app.run(host='0.0.0.0',port=80)
ouput:
5 注册静态目录路由
和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在 创建时指定static_folder参数。
下面的示例将蓝图所在目录下的ezstatic目录设置为静态目录:
admin = Blueprint("admin",__name__,static_folder='ezstatic')
app.register_blueprint(admin,url_prefix='/admin')
默认情况下Flask使用文件夹的名称注册静态文件夹的路由:
+------------------------------------------------------------------+
| url | endpoint | view_function |
+------------------------------------------------------------------+
| /admin/ezstatic | admin.static | Blueprint.send_static_file |
+------------------------------------------------------------------+
现在就可以使用/admin/ezstatic/访问mystatic目录下的静态文件了。
定制静态目录URL规则 :可以在创建蓝图对象时使用static_url_path来改变静态 目录的路由。下面的示例将为ezstatic文件夹的路由设置为/lib:
admin = Blueprint("admin",__name__,static_folder='ezstatic',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')
这时的路由表如下:
+------------------------------------------------------------------+
| url | endpoint | view_function |
+------------------------------------------------------------------+
| /admin/lib | admin.static | Blueprint.send_static_file |
+------------------------------------------------------------------+
这样我们可以使用地址/admin/lib/main.css访问ezstatic目录下的main.css文件了