Flask系列分享: Flask的蓝图使用
使用蓝图进行应用模块化
为了在一个或多个应用中,使应用模块化并且支持常用方案, Flask 引入了 蓝图 概念。蓝图可以极大地简化大型应用并为扩展提供集中的注册入口。 Blueprint
对象与 Flask
应用对象的工作方式类似,但不是 一个真正的应用。它更像一个用于构建和扩展应用的 蓝图 。
为什么使用蓝图?
Flask 中蓝图有以下用途:
- 把一个应用分解为一套蓝图。这是针对大型应用的理想方案:一个项目可以实 例化一个应用,初始化多个扩展,并注册许多蓝图。
- 在一个应用的 URL 前缀和(或)子域上注册一个蓝图。 URL 前缀和(或)子 域的参数成为蓝图中所有视图的通用视图参数(缺省情况下)。
- 使用不同的 URL 规则在应用中多次注册蓝图。
- 通过蓝图提供模板过滤器、静态文件、模板和其他工具。蓝图不必执行应用或 视图函数。
- 当初始化一个 Flask 扩展时,为以上任意一种用途注册一个蓝图。
Flask 中的蓝图不是一个可插拨的应用,因为它不是一个真正的应用,而是一套 可以注册在应用中的操作,并且可以注册多次。那么为什么不使用多个应用对象 呢?可以使用多个应用对象(参见 应用调度 ),但是这 样会导致每个应用都使用自己独立的配置,且只能在 WSGI 层中管理应用。
而如果使用蓝图,那么应用会在 Flask 层中进行管理,共享配置,通过注册按需 改变应用对象。蓝图的缺点是一旦应用被创建后,只有销毁整个应用对象才能注 销蓝图。
蓝图的概念
蓝图的基本概念是:在蓝图被注册到应用之后,所要执行的操作的集合。当分配 请求时, Flask 会把蓝图和视图函数关联起来,并生成两个端点之前的 URL 。
上述内容摘自: dormousehole.readthedocs.io/en/latest/b…
1. 蓝图的简单使用
前面已经讲过,如果需要将一个函数设置为路由,只需要在函数的上方使用 @app.route | get | post(),然后根据装饰器函数需要的参数,写入相应的参数,就能将当前函数映射到指定的路由中,后面访问这个路由地址时,Flask 就会调用对应的映射函数执行相关代码进行处理。
这是处于简单路由的使用,现在换成复杂的情景考虑。 比如现在有一个商品总接口,用来对商品名的增删改查或者批量的增删改查。那么此时,我们设置的路由接口因为:
增加商品: goods/add
删除商品: goods/delete
修改商品: goods/amend
查询商品: goods/query
如果都在 @app.route | get | post() 中实现,也不为不可。但是后期会有其他更多路由接口呢?总不能全部都塞到 @app.route | get | post() 中吧?到时候,就一个.py文件中包含所有路由接口,想要修改哪个路由接口的代码,都要找半天。所以 Flask 考虑到中大型项目对路由接口的进行模块化管理给出了 Blueprint 类,让我们来对需要细分化的路由接口进行细分化成各个模块,进行开发和后期的管理。同时也能通过 Blueprint 的蓝图实例对当前路由接口的 after(请求后)、before(请求前)、error(请求出错)等都能很好的细分化处理。
下面在根目录下创面一个 Blueprints 文件夹用来存放对路由接口模块化的实现。
在 Blueprints/init.py 中,实现了 create_app 函数对 Flask 初始化和对各个 Blueprint 实现。
1.1 根 Blueprint 的简单封装
from flask import Flask
from .root import *
def cerate_app(import_name: str) -> Flask:
app = Flask(import_name)
# 实现根目录路由接口
root_route(app)
return app
# ./Blueprint/root_route.py
from flask import Flask, render_template
def root_route(app: Flask):
@app.get("/")
def index():
return "访问成功"
@app.get("/index")
def index_html():
return render_template("index.html")
在 root.py 函数定义了一个 root_route 函数,并且 root_route 函数接收一个 app 参数,类型为 Flask 类型。
然后使用 @app.route | get | post()来对路由和对应函数进行映射,从这可以看出,实例化的 Flask extend Blueprint 类。
而在 root_route 函数中又定义了两个函数,分别用来处理 "/" 路由和 "/index"路由的请求处理函数。
"/" 路由是返回一段文字。
"/index" 路由是返回一个 .html 文件给浏览器进行展示。
所以当运行 app.py 成功时,就能在浏览器访问对应路由地址,浏览器就会展示对应的内容了。
import os
from Blueprints import cerate_app
app = cerate_app(os.getcwd())
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9999, debug=True)
2 子蓝图的创建和简单示例
上面刚才介绍了一个商品接口的路由例子,现在拿这个路由例子实现下 goodos_blue_print
在上图中,可以看出我们在 Blueprints 文件夹中创建了一个 goods 文件夹用来实现 goods 接口逻辑,代码如下:
from flask import Blueprint
"""
"goods": 设置蓝图类的 name 名称
__name__: __init__.py 所在的文件夹路径
url_prefix="/goods": 指定当前蓝图路由根地址,请注意,这里开头必须带/,并且这里指定的路由地址名称是啥,
那么在浏览器访问时,名称得一致。
"""
goods_blue_print = Blueprint("goods", __name__, url_prefix="/goods")
@goods_blue_print.get("/")
def index():
return "I am a goods interface."
@goods_blue_print.get("/add")
def add():
return "I am a goods add interface."
@goods_blue_print.get("/delete")
def delete():
return "I am a goods delete interface."
@goods_blue_print.get("/revise")
def revise():
return "I am a goods revise interface."
@goods_blue_print.get("/check")
def check():
return "I am a goods check interface."
上面代码为了方便在浏览器访问,所以统一使用了 get 装饰器来实现,实际接口类型需求,按照实际情况来确定。
现在我们前往 Blueprit/init.py 中引入 goods_blue_print 实例,并将其加载到根 Blueprint 中
from flask import Flask
from .root import *
from .goods import goods_blue_print
def cerate_app(import_name: str) -> Flask:
app = Flask(import_name)
# 实现根目录路由接口
root_route(app)
# 使用 Blueprint 实例方法 register_blueprint 加载 goods_blue_print 蓝图
# 这样就确定了 goods_blue_print 蓝图是 app 蓝图的子蓝图。
app.register_blueprint(goods_blue_print)
return app
现在我们去浏览器访问 http://127.0.0.1:9999/goods
获取内容和返回结果一致,说明父子蓝图使用正确。
3. 子蓝图嵌套子蓝图的实现
上面呢,我们实现了, goods_blue_print 加载到了 app Blueprint 中。现在我们再思考下,原先商品表没几个品种,比如,就只有鞋子,袜子,裤子等等,这几个简单的品种。所以不用细分接口,直接使用 goods 接口来实现业务。后来呢,业务扩大,有了帽子类商品,衣服类商品,鞋子类商品等等。而且每个接口实现功能都大相径庭。此时,我们就需要再次在 goods 中来细分蓝图接口模块,让商品接口的实现更加细致化和后期好维护。
我们在 goods 创建了三个文件夹,分别为 caps (帽子) , clothes (衣服), shoes (鞋子) 三个文件夹。分别来处理这三种商品接口的后台逻辑。
./Bluerints/goods/caps/__init__.py
from flask import Blueprint
"""
"caps": 设置蓝图类的 name 名称
__name__: __init__.py 所在的文件夹路径
url_prefix="/caps": 指定当前蓝图路由根地址。
"""
caps_blue_print = Blueprint("caps", __name__, url_prefix="/caps")
print("__name__:", __name__)
@caps_blue_print.get("/")
def index():
return "I am a caps interface."
@caps_blue_print.get("/add")
def add():
return "I am a caps add interface."
@caps_blue_print.get("/delete")
def delete():
return "I am a caps delete interface."
@caps_blue_print.get("/revise")
def revise():
return "I am a caps revise interface."
@caps_blue_print.get("/check")
def check():
return "I am a caps check interface."
其余两个代码一致,只是更改了下开头名称。 现在,前往 Blueprint/goods/init.py 文件中引入这三个蓝图,并一一加载到 goods_blue_print 蓝图中。
from flask import Blueprint
from .caps import caps_blue_print
from .clothes import clothes_blue_print
from .shoes import shoes_blue_print
"""
"goods": 设置蓝图类的 name 名称
__name__: __init__.py 所在的文件夹路径
url_prefix="/goods": 指定当前蓝图路由根地址。
"""
goods_blue_print = Blueprint("goods", __name__, url_prefix="/goods")
@goods_blue_print.get("/")
def index():
return "I am a goods interface."
@goods_blue_print.get("/add")
def add():
return "I am a goods add interface."
@goods_blue_print.get("/delete")
def delete():
return "I am a goods delete interface."
@goods_blue_print.get("/revise")
def revise():
return "I am a goods revise interface."
@goods_blue_print.get("/check")
def check():
return "I am a goods check interface."
def goods_register_blueprint():
for blue_print in [caps_blue_print, clothes_blue_print, shoes_blue_print]:
goods_blue_print.register_blueprint(blue_print)
return goods_blue_print
而后呢,在 Blueprints/init.py 中再次修改代码,原先引入的是 goods_blue_print, 现在修改引入为 goods_register_blueprint 函数。
from flask import Flask
from .root import *
from .goods import goods_register_blueprint
def cerate_app(import_name: str) -> Flask:
app = Flask(import_name)
# 实现根目录路由接口
root_route(app)
# 加载 goods_blue_print 蓝图
app.register_blueprint(goods_register_blueprint())
return app
这样就实现子子蓝图了,现在去浏览器访问下,看是否成功。
都能成功返回对应内容,good。
4. 总结
通过由浅入深的介绍了 Flask 的 Blueprint ,在后期的开发中更好的对接口细分化和为后期更好的维护。下章介绍蓝图中的请求前置函数和请求后置函数,还有请求错误的处理和父子蓝图中间件的实现和分析。
转载自:https://juejin.cn/post/7393551590458490915