# 蓝图 随着程序功能越来越多,为了便于组织,我们把程序功能进行模块化划分, 一个模块负责一类具体内务,这种结构称为蓝图。 简单来说,Blueprint 是一个存储操作方法的容器, Flask 可以通过Blueprint来组织URL以及处理请求。 Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性: - 一个应用可以具有多个Blueprint - 在一个应用初始化时,就应该要注册需要使用的Blueprint - 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名, 即重复使用 - 在一个应用中,一个模块可以注册多次 - Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,也意味着蓝图可以和主程序基本没有耦合,可以随便复用 但是一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中,类似组件。 使用蓝图大概步骤: - 定义蓝图,在一个蓝图内完成一类任务 - 使用蓝图,即注册蓝图,然后属于蓝图的访问会自动导入蓝图内进行处理 ## 蓝图使用案例 我们定义一个蓝图,在我们的教学业务中,学生的注册登录等管理属于用户模块 ,而相应的课程等属于课程模块,我们把这两个定义成蓝图使用。 - 定义蓝图 通过定义蓝图,定义的时候使用`url_prefix`来定义前缀url,这样相同 的前缀就会使用定义好的蓝图,蓝图此时相当于一个子路由。 在下面代码中,我们定义了连个蓝图, `bp1`和`bp2`, 每个分别对应不同的`url`前缀。 # 导入Bluepoint from flask import Blueprint # 定义蓝图,注意参数,不懂的通过 ctr+点击, 进入源代码查看注释 bp1 = Blueprint('user', __name__, url_prefix='/user') bp2 = Blueprint('teaching', __name__, url_prefix='/teaching') # 添加业务处理 # 正常操作 @bp1.route("/login") def user_login(): return "User Login" # 正常操作 @bp1.route("/reg") def user_reg(): return "User Reg" # 正常操作 @bp2.route("/get_course") def teaching_get_course(): return "Teaching get_course" # 正常操作 @bp2.route("/add_course") def teaching_add_course(): return "Teaching add_course" - 使用蓝图 蓝图的使用相对简单,直接导入后注册,如果`url`前缀符合定义的话就会自动的调用蓝图处理。 from flask import Flask # 导入庄子啊蓝图的文件 import bp_apps app = Flask(__name__) app.register_blueprint(bp_apps.bp1) app.register_blueprint(bp_apps.bp2) if __name__ == "__main__": app.run() 在经过上述定义后,我们访问相应url后会有蓝图进行相应处理,比如 访问 `http://127.0.0.1:5000/teaching/add_course` 后会显示对应蓝图的对应处理结果。 ## 蓝图运行机制 - 蓝图保存了一组将来可以在应用对象上执行的操作 - 当在应用对象上调用 route 装饰器注册路由时,这个操作将修改对象的url_map路由表 - 蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项 - 当执行应用对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的路由表 ## 蓝图的url前缀 - 当我们在应用对象上注册一个蓝图时,可以指定一个url_prefix关键字参数(这个参数默认是/) - 在应用最终的路由表 url_map中,在蓝图上注册的路由URL自动被加上了这个前缀, 这个可以保证在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在注册蓝图时将不同的蓝图挂接到不同的自路径即可 - url_for 蓝图中更可以使用`url_for`, 我们在蓝图定义的时候会定义蓝图的`name`关键字值,在 地下路由中也会使用`endpoint`定义端点名称,如果需要使用`url_for`,则可以直接用点号操作。 # name='user' bp1 = Blueprint('user', __name__, url_prefix='/user') ... ... # endpoint='test' @bp1.route("/test", endpoint='test') def user_test(): # 返回的时候使用点号操作 return url_for("user.test")