day92 请求扩展 请求上下文

请求扩展

from flask import Flask,render_template

app=Flask(__name__)

'''
@app.before_request:
是在真正的响应函数之前执行。
可以有多个,当有多个的时候执行顺序是谁在前面就谁先执行
只要有一个before_request有返回值,那么后面所有的before_request都不会执行,真正的响应函数也不会执行
'''
@app.before_request
def befor_process():
    print("befor_process0")
    # return "tt"

@app.before_request
def befor_process1():
    print("befor_process1")

'''
@app.after_request:
after_request是在真正响应函数之后执行的。
他可以有多个,当有多个的时候执行顺序为,谁在前面谁后执行。
before_request的有没有返回值不会影响到after_request的执行
'''
@app.after_request
def after_process(response):
    print("我是请求之后1")
    return response

@app.after_request
def after_process1(response):
    print("我是请求之后2")
    return response

'''
@app.before_first_request:
在项目启动后第一次接收到请求,就会执行这个方法。以后不会执行
'''
@app.before_first_request
def first():
    print(123)

'''
@app.teardown_request:
不管有没有错误,都会执行teardown_request
如果没有错误,错误值为None,如果有错误,直接传递给被装饰的函数
'''
@app.teardown_request
def tre(e):
    print("e",e)

'''
@app.errorhandler(错误码):
如果没有该错误码出现,地下的函数不会执行,如果有该错误码的错误出现就会执行下面的函数,不会让错误暴露给用户
'''
@app.errorhandler(500)
def error_handler(*args,**kwargs):
    print(*args,**kwargs)
    return "500错误"

@app.errorhandler(404)
def errr(e):
    return render_template("index404.html")

'''
@app.template_global():
标签 可以在路由返回的页面中使用 全局的 都可以使用
'''
@app.template_global()
def sb(a1,a2,a3):
    return a1+a2+a3
'''
@app.template_filter():
过滤器 可以在路由返回的页面中使用 全局的 都可以使用
'''
@app.template_filter()
def sb1(a1,a2,a3):
    return a1+a2+a3

@app.route("/index")
def index():
    print("index")
    return render_template("index.html")

if __name__ == '__main__':
    app.run()

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>okok</h1>
<h1>{{sb(1,2,3)}}</h1>
<h1>{{"tank"|sb1(" is ","sb")}}</h1>
</body>
</html>

index404.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>404错误页面</h1>
</body>
</html>

中间件

'''
1 当执行app.run()方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法
2 在__call__里面,执行的是self..wsgi_app(),那么希望在执行他本身的wsgi之前做点事情
3 所有我们先用MyMiddleware类中__init__,保存之前的wsgi,然后我们将app.wsgi转化成MyMiddleware的对象
4 把原来的wsgi.app替换为自定义的
'''
from flask import Flask
app=Flask(__name__)

class MyMiddleware(object):
    def __init__(self,old_wsgi_app):
        self.old_wsgi_app=old_wsgi_app

    def __call__(self, environ, start_response):
        print("123")
        ret=self.old_wsgi_app(environ, start_response)
        print("456")
        return ret

@app.route('/')
def index():
    return "ok"

if __name__ == '__main__':
    app.wsgi_app=MyMiddleware(app.wsgi_app)
    app.run()

偏函数

将所作用的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数的后续参数,原函数有关键字参数的一定要带上关键字,没有的话,按原有参数顺序进行补充。

简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

from functools import partial

def test(a,b,c):
    return a+b+c

tes=partial(test,1,2,4)
#用partial可以得到一个带了参数的函数对象
print(tes())

tes1=partial(test,1,2)
print(tes1(c=5))

蓝图

-app01
	--__init__.py
	--order.py
	--user.py
-run.py

init.py

from flask import Flask
app=Flask(__name__)

from app01 import user
from app01 import order

@app.before_request
def tt1():
    print("我是app的befor——request")


app.register_blueprint(user.us)
app.register_blueprint(order.ord)

order.py

from flask import Blueprint
ord=Blueprint("order",__name__)

@ord.route("/order")
def order():
    return "order"

user.py

from flask import Blueprint,url_for
us=Blueprint("user",__name__)

@us.before_request
def beofor_req():
    print("我是user里面的befor_request")

@us.route("/user")
def index():
    print(url_for("user.order"))
    print(url_for("order.order"))
    return "index"

@us.route("/tt")
def order():
    return "455"

run.py

from app01 import app

if __name__ == '__main__':
    app.run()

loacal对象的补充

# 启动一个多线程,多线程修改一个全局的值,并且要求打印,它自己修改成功之后的那个值
from threading import Thread
import time
from threading import local

# 利用local
'''
cxw = local()
def task(arg):
    cxw.value = arg
    # cxw[线程id][value]=arg
    time.sleep(1)
    # cxw[线程id][value]
    print(cxw.value)
'''

from threading import get_ident

# 用函数的形式模拟local()对象
'''
storage={}
def set(k,v):
    ident=get_ident()
    if ident in storage:
        storage[ident][k]=v
    else:
        storage[ident]={k:v}

def get(k):
    ident=get_ident()
    return storage[ident][k]

def task(arg):
    set("val",arg)
    time.sleep(1)
    v=get('val')
    print(v)
'''

# 面向对象版
'''
class Local:
    storage = {}
    def set(self,k,v):
        ident = get_ident()#获取线程协程的id
        if ident in Local.storage:
            Local.storage[ident][k] = v
        else:
            Local.storage[ident] = {k: v}

    def get(self,k):
        ident = get_ident()
        return Local.storage[ident][k]
obj=Local()
def task(arg):
    obj.set("val", arg)
    time.sleep(1)
    v = obj.get('val')
    print(v)
'''


# 面向对象版的getattr和setattr实现,,每个local对象都有他自己的storage

class Local(object):
    def __init__(self):
        object.__setattr__(self, "storage", {})
        # storage={}

    def __setattr__(self, k, va):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = va
        else:
            self.storage[ident] = {k: va}

    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]


obj = Local()


def task(arg):
    obj.va = arg
    time.sleep(1)
    print(obj.va)


for i in range(10):
    t = Thread(target=task, args=(i,))
    t.start()

请求上下文

1 执行 ctx = self.request_context(environ) 将请求相关的放入ctx


2 ctx.push 方法,把cxt放入到Local对象中的stroage[线程或者协程id][stark]=[ctx,]

3  response = self.full_dispatch_request()这个是请求扩展和响应函数的内容

4 在上述的3中我们可以在任意位置调用 resquest

5 当我们调用request.methons的时候是怎么获取到的?从第二步中存的Local把ctx取出来

6 在ctx在取request

7 然后再从request取methons

原文地址:https://www.cnblogs.com/zqfzqf/p/12392243.html