这里有两种可以使用 BluePrint 的方法
- Folder as working URI 使用文件夹作为一个对应的 URI 的访问路径。http://test.com/api 中 api 对应项目中的一个文件夹
- File as working URI 使用文件作为一个对应的URI 访问路径。http://test.com/api 中 api 对应项目中的一个文件.py
Case 1- Folder as working URI
当前目录文件
./app
├── main (主体模块:主要定义 uri 和 逻辑的 blueprint py 文件)
│ ├── main.py
├── static(静态文件目录:css)
├── templates(模版文件目录:通用 html )
├── app.py
建立 blueprint 的步骤
- 创建一个蓝图的包,其实已经创建了 为main, 作为主要的Web 业务的包,建立蓝图对象 __init__.py
from flask import Blueprint
main = Blueprint('main',__name__)
- 建立一个 views.py 用来保存蓝图使用的视图view
from . import main
@main.route('/')
def home():
return 'index.html'
- 在 __init__.py 中引入,新建的 views.py
from flask import Blueprint
main = Blueprint('main',__name__)
from . import views
- 在主应用 main.py 文件中的 main 对象上注册这个main blueprint 对象
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
现在的app.py 如下
# /app/app.py
from flask import Flask, Response
import os
# 用户应用的 目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
from main.main import app_test
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
app.register_blueprint(blueprint=app_test, url_prefix='/api')
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
if __name__=='__main__':
app.run(debug=True)
Debug
上面的代码在启动的时候会报错:
AttributeError: module 'main.main' has no attribute 'name'
当我们点击进入查看源码的时候,Code 如下
if blueprint.name in self.blueprints:
assert self.blueprints[blueprint.name] is blueprint, (
"A name collision occurred between blueprints %r and %r. Both"
' share the same name "%s". Blueprints that are created on the'
" fly need unique names."
% (blueprint, self.blueprints[blueprint.name], blueprint.name)
)
这就是一个Name Collision 的问题
使用了 app/main/__init__.py 和 /app/main.main.py 两个都标识了自己是 main
为了能继续使用当前的例子,注释掉 main.py
新的目录结构如下
./app
├── main (主体模块:主要定义 uri 和 逻辑的 blueprint py 文件)
│ ├── main.py.bak
│ ├── __init__.py
│ ├── views.py
├── static(静态文件目录:css)
├── templates(模版文件目录:通用 html )
├── app.py
修改一下 app/app.py ,把有 conflict 的地方都注释掉
# /app/app.py
from flask import Flask, Response
import os
# 用户应用的 目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# from main.main import app_test # conflict
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
# app.register_blueprint(blueprint=app_test, url_prefix='/api') # conflict
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
if __name__=='__main__':
app.run(debug=True)
程序跑起来咯
运行机制[^1]
- BluePrint 保存了一组将来可以在应用对象上执行的操作,注册路由 Route 就是一种路径操作
- 当在app对象上调用 route 装饰器注册路由时,这个操作将修改对象的 url_map 路由表
- 然而,蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项 (博主不懂,无脑掠过)
- 当执行app对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的usr_map路由表 (博主不懂,无脑掠过)
FROM:Flask-蓝图(blueprint)
Case 2 - File as working URI
在main 文件夹中加入2个新的文件 product 和 order
./app
├── main (主体模块:主要定义 uri 和 逻辑的 blueprint py 文件)
│ ├── main.py.bak
│ ├── __init__.py
│ ├── views.py
│ ├── login.py
│ ├── order.py
├── static(静态文件目录:css)
├── templates(模版文件目录:通用 html )
├── app.py
# /app/main/login.py
__author__ = '1346478633@qq.com'
from flask import Blueprint,render_template
login = Blueprint('login',__name__)
@login.route('/')
def show():
# return 'Login'
return render_template('login.html') # add the html pages under templates
# /app/main/order.py
__author__ = '1346478633@qq.com'
from flask import Blueprint
'''
创建一个blueprint对象。第一个参数可看做该blueprint对象的姓名
在一个app里,姓名不能与其余的Blueprint对象姓名重复
第二个参数__name__用作初始化
'''
order = Blueprint('order',__name__)
@order.route('/') #将蓝图对象当做'app'那样使用
def login():
return 'Order'
修改一下 app/app.py ,加入新的blueprint
# /app/app.py
from flask import Flask, Response
import os
# 用户应用的 目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# from main.main import app_test # conflict
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
# app.register_blueprint(blueprint=app_test, url_prefix='/api') # conflict
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
from main.login import login
app.register_blueprint(blueprint=login,url_prefix='/login') # 将 main 模块里的蓝图对象account注册到app
from main.order import order
app.register_blueprint(blueprint=order,url_prefix='/order') # 将 main 模块里的蓝图对象order注册到app
if __name__=='__main__':
app.run(debug=True)
测试通过
运行机制
- app.py 文件运行,首先运行目录下面的 __init__.py 文件中的代码 (博主case2例子中没有使用)
- __init__ 文件导入Flask 以及 main 目录下面的py文件
- 接着 __init__ 或者 app 创建Flask对象
- 将 main 目录下面的模块文件注册到蓝图对象中
- app.py 最终运行的就是 __init__.py 和 app.py 中的代码 app 对象