flask中间件及CBV
flask请求扩展、中间件及CBV与蓝图
1、请求扩展(类似于Django中间件)
1、before_first_request
在项目启动后,接收到的第一个请求,就会执行,before_first_request装饰的函数的执行顺序是谁先注册谁先执行
2、before_request
请求没有经过响应函数的时候就会执行before_request装饰的函数,执行顺序是谁先注册谁先执行,如果被装饰的函数有返回值,后面注册的都不会执行,响应函数也不会执行,但是不会影响after_request执行
3、after_request
在before_request与响应函数执行后执行,必须接受响应参数response,并且要将响应参数response返回,执行顺序是谁先注册后执行
from flask import Flask, request app = Flask(__name__) #1执行响应函数之前,相当于django中的process_request @app.before_request def before1(): print('before1') # 在before_request中返回后后续before_request与响应函数都不会执行了 return 'ok' @app.before_request def before2(): print('before2') #after_request必须接收一个参数,参数为Response对象,而且必须返回 @app.after_request def after1(response): print('after1') return response @app.after_request def after2(response): print('after2') return response # 项目启动后接收到的第一个请求,所要执行的函数,这是整个项目的第一次, @app.before_first_request def first(): print('first') @app.route('/') def index(): print('响应函数') return 'ok' if __name__ == '__main__': app.run()
4、teardown_request
一旦遇到错误就会执行传递给装饰的函数,没有错误也会执行,但是错误为None,不能处理错误,只能记录错误
5、errorhandle(错误状态码)
可以对错误进行处理,并且做出相应给用户,必须要传错误状态码,只能传一个值
装饰函数可以返回一个值,也可以返回一个html页面
6、template_global()
相当于Django的标签,可以不用在响应函数中传值给html页面,html可以直接使用装饰的函数名
7、template_filter()
django中的过滤器,第一个参数是你要过滤的那个值,可以不用在响应函数返回值中传,页面可以直接使用,要与函数名同名,html中用 | 来划分过滤的第一个元素
from flask import Flask,request,render_template app = Flask(__name__) @app.teardown_request def tear(e): print(e) print("我是teardown_request") @app.errorhandler(500) def error_500(e): print(e) return "我程序崩了,你下次来把" @app.errorhandler(404) def error_404(e): print(e) return render_template("404.html") #相当于django中的标签。可以不用在响应函数返回值中传,页面可以直接使用,要与函数名同名 @app.template_global() def get_sb(a1,a2): return a1 + a2 #在html中的用法:{{get_sb(1,2)}} #django中的过滤器,第一个参数是你要过滤的那个值,可以不用在响应函数返回值中传,页面可以直接使用,要与函数名同名 @app.template_filter() def get_something(a1,a2,a3,a4): return a1+a2+a3+a4 #在html中的用法:{{1|get_something(2,3,4)}} @app.route("/") def index(): print("我是响应函数") return render_template("index.html") if __name__ == '__main__': app.run()
2、中间件
flask中的中间件本质是在执行wsgi_app的前后执行的叫做中间件
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'ok' class MyMiddleware: # 继承原来的wsgi_app def __init__(self, old_wsgi_app): self.old_wsgi_app = old_wsgi_app # 重写__call__方法实现中间件 def __call__(self, environ, start_response): print('中间件在before之前的执行') ret = self.old_wsgi_app(environ, start_response) print('中间件在after之后的执行') return ret if __name__ == '__main__': # app.__call__() # 源码中推崇这种写法 app.wsgi_app = MyMiddleware(app.wsgi_app) app.run()
3、CBV
路由绑定给类的方式,需要导入views,CBV必须使用路由分发的方式绑定路由,并且路由中要给as_view传参name绑定别名,Index.as_view(name="index")他的作用是返回view对象,我们传递name="index"是给view的__name__改变名字,如果不传,我们没法通过名字来找路由的映射关系,因为都是view
类中设置属性 methods = ["GET"] #规定哪些请求方式可以请求我这个路由
decorators =[tt,] #这个是给我们的响应添加装饰器
1、如果类继承views.View就要用dispatch_request方法
from flask import Flask,views,url_for app = Flask(__name__) def tt(func): def inner(*args,**kwargs): print("你追到我。。") rv = func(*args,**kwargs) print("嘿嘿嘿。。。") return rv return inner class Index(views.View): methods = ["GET"] #规定哪些请求方式可以请求我这个路由 decorators =[tt,] #这个是给 我们的响应添加装饰器 # 如果是views.View就必须是dispatch_request函数 def dispatch_request(self): return "ojbk" # CBV必须用路由分发,也可以用endpoint做反向解析,endpoint要优先于name= app.add_url_rule("/index",view_func=Index.as_view(name="index"),endpoint="index1") # 为什么要给as_view传递name= "index", #1 as_view再语法就要你传, #2 他作用Index.as_view(name="index")他返回是的view这个函数对象,我们传递name="index"是给view的__name__改变名字。如果不传,我没有办法通过名字来找路由的映射关系,因为都是”view“
2、如果类继承views.MethodView就是将dispatch_request方法拆分自定义get与post方法
from flask import Flask,views,url_for app = Flask(__name__) def tt(func): def inner(*args,**kwargs): print("你追到我。。") rv = func(*args,**kwargs) print("嘿嘿嘿。。。") return rv return inner class Login(views.MethodView): methods = ["GET","POST"] # 规定哪些请求方式可以请求我这个路由 #decorators = [tt, ] # 这个是给 我们的响应添加装饰器 # 继承views.MethodView来做路由分发,重写dispatch_request通过请求方法,来找到当前类中的函数 def get(self): print(url_for("index1")) return "get" def post(self): return "post" app.add_url_rule("/login",view_func=Login.as_view(name="login")) if __name__ == '__main__': app.run()
4、蓝图
用来划分目录与指定路由分发,防止循环导入问题
使用:
1、导入蓝图 from flask import Blueprint
2、在视图中注册蓝图 ord = Blueprint("order",__name__)
3、绑定路由用注册的蓝图名绑定路由 @ord.route("/order")
4、在init中注册蓝图 app.register_blueprint(order.ord)
user.py
# 导入蓝图 from flask import Blueprint # 注册蓝图,user是起的别名,在init中注册的时候找到具体是哪个的蓝图 us = Blueprint('user', __name__) # 路由使用蓝图对象 @us.route('/user') def user(): return 'ok'
__init__.py
from flask import Flask app = Flask(__name__) # 导入要执行的函数 from app01 import user # 注册蓝图 app.register_blueprint(user.us)
给单个蓝图加请求扩展直接在蓝图使用
@blog.before_request
如果给全部的蓝图都加上同一个请求扩展是在app中加
@app.before_request
在init注册的时候可以给蓝图加前缀,访问时需要加上前缀
app.register_blueprint(admin, url_prefix='/admin')