flask之蓝图和前后端变量传递
一、蓝图 Blueprint
在Flask中,蓝图(Blueprint)是一种结构化应用程序的方法,特别适用于大型项目。蓝图允许您将应用程序拆分成更小、更可管理的部分,使代码更具模块性和可重用性。
1、蓝图的优势
模块化: 通过蓝图,可以将应用程序的不同部分(比如用户管理、博客模块等)分开,简化管理。
可重用性: 可以在多个应用中使用相同的蓝图模块。
清晰的代码结构: 便于团队协作,因为每个模块相对独立。
2、蓝图的使用步骤
创建蓝图:在py软件包或者py文件中定义,这里以软件包为例子
tree image_manager image_manager ├── __init__.py ├── image_service.py └── views.py
views 是视图函数,定义了路由,__init__.py 文件中执行导入,引用方便
from flask import Blueprint image_bp = Blueprint('image', __name__) from .views import *
补充: image_bp = Blueprint('image', __name__)
这里‘image’ 是蓝图的名字,和路由没有关系
注册蓝图: app.register_blueprint(bpname_bp, url_prefix=config.APP_URL_PREFIX)
应用程序中注册这个蓝图,通常是在app.py
或类似的主应用程序文件中。
from flask import Flask, render_template, redirect, url_for from flask_cors import CORS app = Flask(__name__, template_folder='template', static_folder="static", static_url_path=config.APP_URL_PREFIX) CORS(app, supports_credentials=True) app.config['SESSION_COOKIE_NAME'] = '/serviceops' app.config['SECRET_KEY'] = 'hello-healsci-service-ops' # 注册蓝图 app.register_blueprint(image_bp, url_prefix=config.APP_URL_PREFIX) @app.errorhandler(500) def ERROR_500(e): return render_template('500.html', message=e.description) @app.errorhandler(404) def ERROR_404(e): return render_template('404.html') @app.route('/') @login_required def root_path(): return redirect(url_for('swarm.service_list')) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
注册时,可以指定url_prefix
来为蓝图中的所有路由加上一个公共的URL前缀。
定义路由: 使用装饰器 @bpname_bp.route('/xxx')
@image_bp.route('/images') @login_required def image_list(): image_list = get_image_list(config.master_ip) image_file_list = get_files_from_server_path() mount_path = get_image_upload_mount_path() return render_template('images.html', image_list=image_list, image_file_list=image_file_list, mount_path=mount_path)
由于蓝图在注册时被指定了url_prefix
,真正的访问路径是<url_prefix>/images
,
路由实现的过程
- 蓝图名称(
swarm
): 仅用于内部标识,和某些工具或调试日志有关,但不影响URL。 url_prefix
: 用于定义蓝图内所有路由的公共前缀。- 具体路由: 在蓝图内通过
@swarm_bp.route(xxx)
定义的路径。 - 最终路径: 由
url_prefix
和具体路由结合,形成完整的路径,即http://ip/xxx/xxx
。
3、项目结构建议
对于大型项目,建议将蓝图放在模块或包内,比如:
tree service-ops service-ops ├── Dockerfile ├── Jenkinsfile ├── README.md ├── app.py ├── app_util.py ├── build_info.txt ├── config.py ├── db │ └── db_operation.py ├── docker-entrypoint.sh ├── gunicorn.conf.py ├── healthcheck.csv ├── image_manager │ ├── __init__.py │ ├── image_service.py │ └── views.py ├── monitor_expr.csv ├── pip.conf ├── release_version.txt ├── requirements.txt ├── schedule │ ├── __init__.py │ └── task.py ├── scripts │ └── check.sh ├── sources.list ├── static │ ├── css │ │ ├── bootstrap3.3.0.min.css │ │ └── jquery-ui-1.10.4.css │ └── js │ ├── bootstrap3.3.0.min.js │ ├── echarts.js │ ├── healsci_alarm.js │ ├── jquery-ui-1.10.4.js │ ├── jquery3.5.1.min.js │ └── jsencrypt.js ├── template │ ├── 404.html │ ├── 500.html │ ├── add_service.html │ ├── container_log.html ├── tests │ ├── data │ │ └── docker_api_service.json │ ├── test_monitor_jmeter.py │ ├── test_monitor_service.py │ ├── test_std_dataset_service.py │ └── test_swarm_service.py └── user_manager ├── __init__.py ├── user_service.py └── views.py
二、前端引用后端的变量
在Flask项目中,将变量传输到前端HTML页面的常用方式是通过render_template
函数。该函数用于渲染模板,并允许你将Python变量传递给模板以供使用。在Flask中,有几种方法可以将数据传输到前端HTML页面:
1、render_template
这是Flask中最直观和常用的方法。你可以在调用render_template
时,将变量作为关键字参数传递给模板,在Jinja2模板中直接使用这些变量。
from flask import render_template def image_list(): image_list = get_image_list(config.master_ip) image_file_list = get_files_from_server_path() mount_path = get_image_upload_mount_path() return render_template('images.html', image_list=image_list, image_file_list=image_file_list, mount_path=mount_path)
在images.html
中,你可以通过Jinja2语法来访问这些变量:
<ul> {% for image in image_list %} <li>{{ image }}</li> {% endfor %} </ul> <p>Mount Path: {{ mount_path }}</p>
2、flask.jsonify
如果你需要在前端以JavaScript方式处理数据,尤其是通过AJAX请求时,可以使用flask.jsonify
来返回JSON格式数据。
from flask import jsonify @app.route('/api/images') def api_image_list(): image_list = get_image_list(config.master_ip) return jsonify(image_list=image_list)
然后在JavaScript中通过AJAX请求处理:
fetch('/api/images') .then(response => response.json()) .then(data => { console.log(data.image_list); });
3、 session
和 g
对象
在Flask中,session
对象可以用于在用户会话中存储变量,而g
对象用于在请求上下文中存储数据。这些数据可以在渲染模板时访问。
from flask import Flask, render_template, g, session app = Flask(__name__) app.secret_key = 'jingzhiz' @app.before_request def before_request(): g.user = 'jingzhiz' session['info'] = {'爱好': '洗脚', '年龄': 18, '性别': '男'} @app.route('/') def index(): # put application's code here # raise Exception('测试异常') return '这里是根路径返回的结果' @app.route('/home') def home(): return render_template('home.html') if __name__ == '__main__': app.run()
在html模版中访问
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <p>使用标签:{{ add(5,6) }}</p> <p>使用过滤器:{{ "Hello, World!" | reverse }} </p> <p>User: {{ g.user }}</p> <p>Session Data: {{ session['info']['爱好'], session['info']['年龄'] }}</p> </head> <body> </body> </html>
4、全局上下文处理器 @app.context_processor
@app.template_global() 也有类似的作用
全局上下文处理器可以用于在每个模板中自动提供一些变量。
@app.context_processor def inject_user(): return dict(user=get_current_user())
这使得每个模板自动具备user
变量:
<p>User: {{ user }}</p>
这些方法可以根据你的具体需求和使用场景进行适当选择。
render_template
是最直接的选择,特别适用于基本的服务器端渲染,而jsonify
更适合用于AJAX请求和动态页面的数据交互。
使用session
或g
对象可以在请求间或用户会话中共享数据,而全局上下文处理器方便应用程序全局的变量注入。