Flask 蓝图(Blueprint)
蓝图使用起来就像应用当中的子应用一样,可以有自己的模板,静态目录,有自己的视图函数和URL规则,蓝图之间互相不影响。但是它们又属于应用中,可以共享应用的配置。对于大型应用来说,我们可以通过添加蓝图来扩展应用功能,而不至于影响原来的程序。不过有一点要注意,目前Flask蓝图的注册是静态的,不支持可插拔。
创建一个蓝图
比较好的习惯是将蓝图放在一个单独的包里,所以让我们先创建一个”admin”子目录,并创建一个空的”__init__.py”表示它是一个Python的包。现在我们来编写蓝图,将其存在”admin/admin_module.py”文件里:
from flask import Blueprint
admin_bp = Blueprint('admin', __name__)
@admin_bp.route('/')
def index(name):
return '<h1>Hello, this is admin blueprint</h1>'
我们创建了蓝图对象”admin_bp”,它使用起来类似于Flask应用的app对象,比如,它可以有自己的路由”admin_bp.route()”。初始化Blueprint对象的第一个参数’admin’指定了这个蓝图的名称,第二个参数指定了该蓝图所在的模块名,这里自然是当前文件。
接下来,我们在应用中注册该蓝图。在Flask应用主程序中,使用”app.register_blueprint()”方法即可:
from flask import Flask
from admin.admin_module import admin_bp app = Flask(__name__)
app.register_blueprint(admin_bp, url_prefix='/admin') if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
“app.register_blueprint()”方法的”url_prefix”指定了这个蓝图的URL前缀。现在,访问”http://localhost:5000/admin/”就可以加载蓝图的index视图了。
你也可以在创建蓝图对象时指定其URL前缀:
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
这样注册时就无需指定:
app.register_blueprint(admin_bp)
蓝图资源
蓝图有自己的目录,它的所有资源都在其目录下。蓝图的资源目录是由创建Blueprint对象时传入的模块名”__name__”所在的位置决定的。同时,我们可以指定蓝图自己的模板目录和静态目录。比如我们创建蓝图时传入:
admin_bp = Blueprint('admin', __name__,
template_folder='templates',
static_folder='static')
这样,该蓝图的模板目录就在”admin/templates”下,而静态目录就在”admin/static”下。当然,其实默认值就是这两个位置,不指定也没关系。我们可以用蓝图对象的”root_path”属性获取其主资源路径,”open_resource()”方法访问主资源路径下的某个文件,比如:
# 假设 current app 在路径 /home/bjhee/flask-app,
#这个将会返回 /home/bjhee/flask-app/admin
print admin_bp.root_path
# 读取文件 /home/bjhee/flask-app/admin/files/info.txt
with admin_bp.open_resource('files/info.txt') as f:
info = f.read()
print info
构建URL
构建URL的方法”url_for()”。其第一个参数我们称为端点(Endpoint),一般指向视图函数名或资源名。蓝图的端点名称都要加上蓝图名为前缀,创建Blueprint对象时的第一个参数是蓝图名字,当我们通过端点名称来获取URL时,我们要这样做:
from flask import url_for
url_for('admin.index') # return /admin/
url_for('admin.static', filename='style.css') # return /admin/static/style.css
这样才能获得’admin’蓝图下视图或资源的URL地址。如果,”url_for()”函数的调用就在本蓝图下,那蓝图名可以省略,但必须留下”.”表示当前蓝图:
url_for('.index')
url_for('.static', filename='style.css')
蓝图在国际化中的使用
@app.route('/<lang_code>/')
def index(lang_code):
g.lang_code = lang_code
return '<h1>Index of language %s</h1>' % g.lang_code
@app.route('/<lang_code>/path')
def path(lang_code):
g.lang_code = lang_code
return '<h1>Language base URL is %s</h1>' % url_for('index', lang_code=g.lang_code)
每个路由都要加”<lang_code>”参数,而且每个视图函数都要将这个参数保存在上下文环境变量中以便其他地方使用,能不能简化呢?让我们创建一个以参数做URL前缀的蓝图吧:
from flask import Blueprint, g, url_for
lang_bp = Blueprint('lang', __name__, url_prefix='/<lang_code>')
@lang_bp.route('/')
def index():
return '<h1>Index of language %s</h1>' % g.lang_code
@lang_bp.route('/path')
def path():
return '<h1>Language base URL is %s</h1>' % url_for('.index', lang_code=g.lang_code)
将上面的代码保存在”lang_module.py”中,然后在应用主程序里注册:
from lang_module import lang_bp app.register_blueprint(lang_bp)
这样做的确省去了每个路由加”<lang_code>”参数的麻烦,但如果运行了该程序,会发现报错。因为在视图中没有”lang_code”传进来,所以也没地方设置这个”g.lang_code”变量。这里,我们就要用到URL预处理器了,让我们回到蓝图代码”lang_module.py”,加上下面的函数:
@lang_bp.url_value_preprocessor
def get_lang_code_from_url(endpoint, view_args):
g.lang_code = view_args.pop('lang_code')
这个”@lang_bp.url_value_preprocessor”装饰器表明,它所装饰的函数,会在视图函数被调用之前,URL路径被预处理时执行。而且只针对当前蓝图的所有视图有效。它所传入的第二个参数,保存了当前请求URL路径上的所有参数的值。所以,上面的”get_lang_code_from_url()”函数就可以在URL预处理时,设置”g.lang_code”变量。这样,视图函数中就可以取到”g.lang_code”,而我们的程序也能够正常运行了。
还有可以优化的地方。每次调用”url_for()”来构建路径时,必须给”lang_code”参数赋上值。这个是否也可以统一处理?我们再加上一个函数:
from flask import current_app @lang_bp.url_defaults
def add_language_code(endpoint, values):
if 'lang_code' in values or not g.lang_code:
return
if current_app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
values['lang_code'] = g.lang_code
这个”@lang_bp.url_defaults”装饰器所装饰的函数,会在每次调用”url_for()”时执行,也只对当前蓝图内的所有视图有效。它就可以在构建URL时,设置url规则上参数的默认值,你只需将参数名及其默认值保存在函数的第二个参数values里即可。
”current_app.url_map.is_endpoint_expecting()”是用来检查当前的端点是否必须提供一个”lang_code”的参数值。因为我们这个蓝图里的所有端点都包含前缀”<lang_code>”,这种情况下”is_endpoint_expecting”检查可以省去,所以上面的函数可以简化为:
@lang_bp.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', g.lang_code)
现在,我们就可以将视图函数”url_for()”简写为:
@lang_bp.route('/path')
def path():
return '<h1>Language base URL is %s</h1>' % url_for('.index')
最终代码
from flask import Blueprint, g, url_for
lang_bp = Blueprint('lang', __name__, url_prefix='/<lang_code>')
@lang_bp.route('/')
def index():
return '<h1>Index of language %s</h1>' % g.lang_code
@lang_bp.route('/path')
def path():
return '<h1>Language base URL is %s</h1>' % url_for('.index')
@lang_bp.url_value_preprocessor
def get_lang_code_from_url(endpoint, view_args):
g.lang_code = view_args.pop('lang_code')
# 设置url规则上参数的默认值
@lang_bp.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', g.lang_code)
Flask 蓝图(Blueprint)的更多相关文章
- 测试平台系列(4) 使用Flask蓝图(blueprint)
使用Flask蓝图(blueprint) 回顾 先来看一下上一篇的作业吧,使用「logbook」的时候,遇到了时区不对的情况.那么我们怎么去解决这个问题呢? 实际上logbook默认采用的是世界标准时 ...
- 5. 使用Flask蓝图(blueprint)
一直到现在都没有怎么写代码,可能更得比较慢. 作业回顾 先来看一下文章4的作业吧,使用logbook的时候,遇到了时区不对的情况.那么我们怎么去解决这个问题呢? 实际上logbook默认采用的是世界标 ...
- Python Flask 蓝图Blueprint
1. 目录结构 2. manage.py类似于django中manage import fcrm if __name__ == '__main__': fcrm.app.run(port=8001) ...
- Flask蓝图Blueprint和特殊装饰器
Flask 中的 蓝图 Blueprint 不能被run的flask实例:相当于django中的app01 应用 蓝图作用:功能隔离 路由隔离 Blueprint就是 一个不能run的flask 蓝图 ...
- flask蓝图blueprint是什么
蓝图 blueprint 简单的说,就是帮助我们对flask程序进行目录结构的划分:django项目创建时,是自动生成项目目录,而在flask这里,需要我们自己来规划,这就需要blueprint来将整 ...
- Flask蓝图(Blueprint)
一.作用 1.目录结构划分 2.url添加前缀 url_prefix 3.应用特殊装饰器,在该蓝图定义的特殊装饰器,只在改蓝图的起效 二.简单示例 1.创建一个项目文件 2.创建一个同名的python ...
- 第九篇 Flask 中的蓝图(BluePrint)
第九篇 Flask 中的蓝图(BluePrint) 蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? ...
- Flask最强攻略 - 跟DragonFire学Flask - 第九篇 Flask 中的蓝图(BluePrint)
蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...
- python 全栈开发,Day120(路由系统, 实例化Flask的参数, 蓝图(BluePrint), before_request after_request)
昨日内容回顾 1.Flask: from flask import Flask app = Flask(__name__) # 从源码中可以看出,Flask集成的run方法是由werkzeug中的ru ...
随机推荐
- [Luogu3121][USACO15FEB]审查Censoring
题面 sol 开一个栈记录依次经过的\(AC\)自动机上的节点编号以及这一次的字母,若匹配到一个串就直接弹掉栈顶的\(len\)个元素,\(len\)为匹配到的模式串长度.弹栈顶直接\(top-=le ...
- HDU4812
树分治 求逆元请递推,不然会TLE 开桶记录即可 注意常数 # pragma comment(linker,"/STACK:102400000,102400000") # incl ...
- link 标签
link标签 主要是引用外部文件 rel属性 规定当前文档与被链接文档之间的关系 alternate,author,help,icon,licence,next,pingback,prefetch,p ...
- Android开发——设置界面的创建
前言: 最近忙着搞项目,难得有时间,便来整理搞项目中学习到的知识 使用之前,先介绍一下android这种的五种数据储存方式,分别为文件储存,SharePrefence,SQL,使用ContentPro ...
- doT.js——前端javascript模板引擎问题备忘录
我手里维护的一个项目,遇到一个问题:原项目的开发人员在Javascript中,大量的拼接HTML,导致代码极丑,极难维护.他们怎么能够忍受的了这么丑陋.拙劣的代码呢,也许是他们的忍受力极强,压根就没想 ...
- OpenStack中的rabbitmq的配置方法
OpenStack中的rabbitmq的配置方法 author:headsen chen 2017-10-11 17:24:58 个人原创,允许转载,转载请注明作者,出处,否则依法追究法律责任 ...
- python web开发-flask读取txt文件内容
某些情况下,需要读取flask网站要目录下的txt文件.但是直接在flask网站的目录下创建一个文件是无法访问的.从网站找了一些资料,最终发现通过写一个方法返回txt内容比较简单方便,不过此方法适用于 ...
- 关于SQL性能优化的十条经验
1.查询的模糊匹配 尽量避免在一个复杂查询里面使用 LIKE '%parm1%'—— 红色标识位置的百分号会导致相关列的索引无法使用,最好不要用. 解决办法: 其实只需要对该脚本略做改进,查询速度便会 ...
- 快速理解web语义化
什么是Web语义化 Web语义化是指使用恰当语义的html标签.class类名等内容,让页面具有良好的结构与含义,从而让人和机器都能快速理解网页内容.语义化的web页面一方面可以让机器在更少的人类干预 ...
- IMLite轻量级即时通信工具开发指南
花了一周时间开发了一个简单的即时通信工具,勉强算是程序原型.现在我把开发流程和一些个人的想法记录下来.本文首先介绍程序架构和通信接口,之后会聚焦到服务器的信号槽设计原则,接下来将解释有关TCP通信的粘 ...