文章目录
1. 上下文简介
- 上下文理解
- 常驻内存中的全局变量
- 程序运行状态与相关资源的合集
- 操作系统调度/进程切换时需要保存的值
- 参考文档
https://dormousehole.readthedocs.io/en/latest/templating.html#id6
- Flask上下文源码
# globals.py
# -*- coding: utf-8 -*-
"""
flask.globals
~~~~~~~~~~~~~
Defines all the global objects that are proxies to the current
active context.
:copyright: 2010 Pallets
:license: BSD-3-Clause
"""
from functools import partial
from werkzeug.local import LocalProxy
from werkzeug.local import LocalStack
_request_ctx_err_msg = """\
Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.\
"""
_app_ctx_err_msg = """\
Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.\
"""
def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)
def _lookup_app_object(name):
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return getattr(top, name)
def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app
# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))
- 参考文档
https://blog.csdn.net/yournevermore/article/details/88802371
2. 标准环境
2.1 应用上下文变量
- 应用上下文:应用内都可访问
- current_app
- 生命周期:当前程序实例,多个程序会有多个current_app,重运行后不再是新的实例
- g
- 生命周期:一次请求周期,下次请求不再是当前g,不可以跨请求
2.2 请求上下文变量
- 请求上下文:请求内可访问的内容
- request
- 生命周期:一次请求周期,下次请求不再是当前request,不可以跨请求
- 不同的用户会会创建不同的request,
- session
- 生命周期:会话级,只要当前session未过期,可以跨请求
2.3 参考博客
https://segmentfault.com/a/1190000017814222
https://blog.csdn.net/m0_37323771/article/details/80645100
2.4 其他缺省全局变量
- 缺省情况下,
g
、session
、request
全局变量可以在 Jinja2 模板中使用,除此之外,还有config
和url_for()
config
: 当前配置对象( flask.config ),也可以使用config.py配置文件url_for()
函数
2.5 案例Code
# demo.py
from flask import Flask,session, render_template, request, g
import os
from datetime import timedelta
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
@app.route('/<username>')
def hello(username):
session['username'] = username
g.id = request.args.get("id")
return render_template('session.html')
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=>, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<p>{{ session }}</p>
<p>{{ session.username | default("游客") }}</p>
<p>{{ request }}</p>
<p>{{ request.args["id"] | default("id") }}</p>
<p>{{ g }}</p>
<p>{{ g.id }}</p>
<p>{{ g['id']| default('你好') }}</p>
</div>
</body>
</html>
访问: http://127.0.0.1:5000/username?id=123
3. 环境处理器
- @app.context_processor
- 环境处理器,也叫上下文处理器,在模板被渲染前运行,
作用是把新的变量自动引入模板环境中
- 被改装饰器修饰的钩子函数返回一个字典,字典中的
key
会被模板中当成变量来渲染返回的字典不仅可以包含变量,也可以包含方法,切方法可以在模板中调用
@app.route('/')
def demo():
return render_template('demo.html')
# 环境处理器
@app.context_processor
def my_context_processor():
def add(n):
return n + n
return dict(username='zhangsan', func_add=add)
<body>
<p>{{ username }}</p> # zhangsan
<p>{{ func_add(4) }}</p> # 8
</body>
- before_request:
装饰器/钩子函数
在请求/视图函数之前执行的
4. 全局函数
4.1 内置全局函数
- dict()函数,方便生成字典型变量
{% set user=dict(name='zhangsan', age=18) %}
{{ user }}
# {'name': 'zhangsan', 'age': 18}
- joiner()函数,分隔符函数
{% set sep = joiner(' | ') %}
{% for item in range(1,10) %}
{{ sep() }}<span>{{ item }}</span>
{% endfor %}
# 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
- cycler()函数
{% set cycle = cycler('odd', 'even') %}
<ul>
{% for num in range(10,20,2) %}
<li>Num is "{{ num }}", next line is "{{ cycle.current }}" line.</li>
{% endfor %}
</ul>
>
Num is "10", next line is "odd" line.
Num is "12", next line is "odd" line.
Num is "14", next line is "odd" line.
Num is "16", next line is "odd" line.
Num is "18", next line is "odd" line.
4.2 自定义全局函数
- 方式一:
@app.template_global('name')
@app.template_global('func1')
def my_add(a, b):
return a + b
<p>{{ func1(2, 3) | default('没有调用函数')}}</p>
- 方式二:
app.add_template_global(func, 'name')
def my_add(a, b):
return a + b
app.add_template_global(my_add, 'func1')
5. 钩子函数
- 使用场景
- 在请求开始时,建立数据库连接;
- 在请求开始时,根据需求进行权限校验;
- 在请求结束时,指定数据的交互格式;
- 常用钩子函数
before_first_request
:在处理第一个请求前执行before_request
:请求已到达Flask,但还没有进入到具体的视图函数之前调用,一般用来处理后面需要用到的数据after_request
:如果没有抛出错误,在每次请求后可以修改视图函数的响应,必须要有return,且视图函数执行失败不会再执行。teardown_request
:在每次请求后执行teardown_appcontext
:异常处理。不管是否有异常,注册的函数 都会在每次请求之后执行。template_filter
:自定义过滤器时使用context_processor
:见上文errorhandler
:异常响应吗处理
- g与钩子函数操作数据库
def connect_db():
conn = pymysql.connect(**{
'host':'ip',
'user':'root',
'password':'123456',
'port': 3306 ,
'database':'db01', #指定你的数据库名
})
return conn.cursor()
@app.before_request
def do_db():
if 'db' not in g:
g.db = connect_db()
@app.teardown_request
def teardown_db(exception):
db = g.pop('db', None)
if db is not None:
print('关闭游标')
db.close()
@app.route('/')
def index():
sql = 'select * from t_book ;'
g.db.execute(sql)
r = g.db.fetchall()
if len(r) !=0:
return '数据表有数据'
return '数据表为空'