flask框架(七)
蓝图
作用:对程序进行目录结构划分
不使用蓝图情况下,自己分文件
目录结构:
-templates
-views
-__init__.py
-user.py
-order.py
-app.py
app.py
from views import app
if __name__ == '__main__':
app.run()
init.py
from flask import Flask,request
app = Flask(__name__)
#不导入这个不行
from . import account
from . import order
from . import user
user.py
from . import app
@app.route('/user')
def user():
return 'user'
order.py
from . import app
@app.route('/order')
def order():
return 'order'
使用蓝图 (Blueprint)
目录结构:
-app01
-pro
-templates
-__init__.py
-views
-manage.py
manage.py
from pro import app
if __name__ == '__main__':
app.run()
init.py
from flask import Flask
app=Flask(__name__)
from pro import views
app.register_blueprint(views.us)
views.py
from flask import Blueprint,render_template
us=Blueprint("user",__name__)
@us.route("/")
def index():
return render_template("index.html")
总结:
1 xxx = Blueprint('account', name,url_prefix='/xxx') :蓝图URL前缀,表示url的前缀,在该蓝图下所有url都加前缀
2 xxx = Blueprint('account', name,url_prefix='/xxx',template_folder='tpls'):给当前蓝图单独使用templates,向上查找,当前找不到,会找总templates
3 蓝图的befort_request,对当前蓝图有效
4 大型项目,可以模拟出类似于django中app的概念
请求上下文源码分析
第一阶段:将ctx(request,session)放到Local对象上
第二阶段:视图函数导入:request/session
request.method
-LocalProxy对象.method,执行getattr方法,getattr(self._get_current_object(), name)
-self._get_current_object()返回return self.__local(),self.__local(),在LocakProxy实例化的时候,object.__setattr__(self, '_LocalProxy__local', local),此处local就是:partial(_lookup_req_object, 'request')
-def _lookup_req_object(name):
top = _request_ctx_stack.top #_request_ctx_stack 就是LocalStack()对象,top方法把ctx取出来
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)#获取ctx中的request或session对象
第三阶段:请求处理完毕
- 获取session并保存到cookie
- 将ctx删除
程序运行,两个LocalStack()对象,一个里面放request和session,另一个放g和current_app
g对象
专门用来存储用户信息的g对象,g的全称的为global
g对象的特性:
当前请求内你设置就可以取,必须先设置,后取,当前请求可以取无限次。就算你在当前请求设置了g对象,如果不取,其他的请求也取不到。
g对象和session的区别
session对象是可以跨request的,只要session还未失效,不同的request的请求会获取到同一个session,但是g对象不是,g对象不需要管过期时间,请求一次就g对象就改变了一次,或者重新赋值了一次
代码示例:
from flask import Flask,g,redirect
app=Flask(__name__)
def set_g():
g.name='sb' #设置g(可以单独这样设置,也可以在视图函数内设置,直接g.属性名设置)
@app.route("/")
def index():
set_g()
return redirect("/index")
@app.route("/index")
def login():
print(g.name) #获取g对象
return "2"
if __name__ == '__main__':
app.run()
信号
Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为
安装:pip install blinker
内置信号:
request_started = _signals.signal('request-started') # 请求到来前执行
request_finished = _signals.signal('request-finished') # 请求结束后执行
before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
template_rendered = _signals.signal('template-rendered') # 模板渲染后执行
got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行
request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 应用上下文执行完毕后自动执行(无论成功与否)
appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') # 调用flask在其中添加数据时,自动触发
使用信号:
from flask import Flask,signals
app = Flask(__name__)
#给信号绑定要执行的函数
#无需管调用,因为flask,已经给我们设置调用点
def func(*args,**kwargs):
print('触发型号',args,kwargs)
#与该信号进行绑定
signals.request_started.connect(func) #绑定信号,请求到来前就会执行绑定的函数
# 触发信号: signals.request_started.send()
@app.before_first_request
def before_first1(*args,**kwargs):
print("befor_first_request")
@app.before_request
def before_first3(*args,**kwargs):
print("befor_request")
@app.route('/',methods=['GET',"POST"])
def index():
print('视图')
return "视图"
一个信号触发点的流程:(了解知识点)
a. before_first_request
b. 触发 request_started 信号
c. before_request
d. 模板渲染
渲染前的信号 before_render_template.send(app, template=template, context=context)
rv = template.render(context) # 模板渲染
渲染后的信号 template_rendered.send(app, template=template, context=context)
e. after_request
f. session.save_session()
g. 触发 request_finished信号
如果上述过程出错:
触发错误处理信号 got_request_exception.send(self, exception=e)
h. 触发信号 request_tearing_down
自定义信号(了解)
from flask import Flask
from flask.signals import _signals
app = Flask(import_name=__name__)
# 自定义信号
xxxxx = _signals.signal('xxxxx')
def func(sender,a):
print(sender,a)
print("我是自定义信号")
# 自定义信号中注册函数
xxxxx.connect(func)
@app.route("/x")
def index():
# 触发信号
xxxxx.send("sb",a="1") #最少传递一个参数
return 'Index'
if __name__ == '__main__':
app.run()
flask-session
作用:将默认保存的签名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy
安装:pip3 install flask-session
使用1 (复杂的方式)
from flask import Flask,session
from flask_session import RedisSessionInterface
import redis
app = Flask(__name__)
app.secret_key="ajksda"
conn=redis.Redis(host='127.0.0.1',port=6379)
#use_signer设置是否需要secret_key签名,permanent设置关闭浏览器cookie是否失效
app.session_interface=RedisSessionInterface(conn,key_prefix='jason',use_signer=True, permanent=False)
@app.route('/')
def hello_world():
session['sb']='jason'
return 'Hello World!'
@app.route("/index")
def index():
print(session['sb'])
return "ok"
if __name__ == '__main__':
app.run()
使用2 (简单的方式)
from flask import Flask,session
import redis
from flask_session import Session
app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] =redis.Redis(host='127.0.0.1',port='6379')
app.config['SESSION_KEY_PREFIX']="jason"
Session(app)
@app.route('/')
def hello_world():
session['sb']='jason'
return 'Hello World!'
@app.route("/index")
def index():
print(session['sb'])
return "ok"
if __name__ == '__main__':
app.run()