• flask之中间件、蓝图、请求上下文等相关内容-142


    1 中间件

    from flask import Flask

    app = Flask(__name__)


    @app.route('/')
    def index():
       return 'Hello World!'


    # 模拟中间件
    class Md(object):
       def __init__(self, old_wsgi_app):
           self.old_wsgi_app = old_wsgi_app

       def __call__(self, environ, start_response):
           print('开始之前')

           ret = self.old_wsgi_app(environ, start_response)
           print('结束之后')
           return ret


    if __name__ == '__main__':
       # 1我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法
       # 2 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
       # 3 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
       # 4 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
       # 把原来的wsgi_app替换为自定义的,
       aaa=Md(app.wsgi_app)
       app.wsgi_app = aaa
       app.run()
       # flask请求来了会执行,执行app()--->触发:类的__call__
       # app.__call__---->self.wsgi_app(environ, start_response)
       # 请求来了以后,会执行Md对象的__call__
       # aaa(environ, start_response)--->Md类的__call__()

     

    2 蓝图

    1 是一个类的对象,用来划分项目目录,为了避免使用app划分目录的时候出现循环导入问题
    2 使用步骤
    -实例化得到一个蓝图对象
           from flask import Blueprint
           account = Blueprint('account', __name__)
       -像使用app一样使用蓝图,注册路由
      @account.route('/login.html', methods=['GET', "POST"])
           def login():
               return render_template('login.html')
           
       -在app中注册蓝图
      from .views.account import account
      app.register_blueprint(account)
           
    3 注意点:
    1 蓝图注册进app时,指定前缀(类似于路由分发)
      app.register_blueprint(admin, url_prefix='/admin')
       2 蓝图对象在实例化的时候,可以指定当前蓝图使用哪个模板文件夹和静态文件夹
       如果不指定,默认用app的,查找顺序是先从自己里面找,找不到再找app的
      web = Blueprint('web',__name__,template_folder='templates',static_folder='static')
           
       3 蓝图对象有自己的请求扩展,请求扩展只属于当前蓝图
       # 只有访问当前蓝图管理的路径才会触发请求扩展
       web = Blueprint('web', __name__,template_folder='templates',static_folder='static')
       @web.before_request
       def web_request():
           print('web request')
       @web.after_request
       def web_after(response):
           print(response)
           return response

    3 flask请求上下文

    1 当flask启动,等待客户端请求
    2 一旦请求来了:app()--->app.__call__()---->app.wsgi_app()
    3 wsgi_app()源码如下:
       # environ:http请求字典
       # 返回一个ctx=RequestContext,对象中有Request对象,Session对象。。。
       ctx = self.request_context(environ)
       error = None
       try:
           try:
                   # 把ctx对象放到了全局变量_request_ctx_stack中
                   # _request_ctx_stack全局变量是LocalStack的对象
                   # LocalStack类的push方法
                   '''
                          def push(self, obj):
                              rv = getattr(self._local, "stack", None)
                              if rv is None:
                                  self._local.stack = rv = []
                              rv.append(obj)
                              return rvbefore_first_request,before_request,after_request
                          '''
                   ctx.push()
                   # 执行请求扩展的东西(before_first_request,before_request,after_request)
                   # 根据路径执行视图函数
                   response = self.full_dispatch_request()
               except Exception as e:
                   error = e
                   response = self.handle_exception(e)
                   except:
                       error = sys.exc_info()[1]
                       raise
                       return response(environ, start_response)
               finally:
                    if self.should_ignore_error(error):
                         error = None
                         ctx.auto_pop(error)



     

     

     

     

    补充

    1 requirements.txt

    1 在虚拟环境中直接导出
    pip3 freeze >requirements.txt
    2 系统环境装了很多模块,只导出当前项目依赖的模块
    -pip3 install pipreqs
       -pipreqs ./ --encoding=utf8

    2 方法和函数的区别

    from types import MethodType,FunctionType

    class Foo(object):
    def fetch(self):
    pass

    # print(isinstance(Foo.fetch,MethodType))
    # print(isinstance(Foo.fetch,FunctionType)) # True

    obj = Foo()
    print(isinstance(obj.fetch,MethodType)) # True
    print(isinstance(obj.fetch,FunctionType))

    3 threading.local


    # 不用local,会出现并发安全的问题
    # from threading import Thread
    # import time
    # lqz = -1
    # def task(arg):
    #     global lqz
    #     lqz = arg
    #     # time.sleep(2)
    #     print(lqz)
    #
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()


    # 使用local
    # from threading import Thread
    from threading import local
    # import time
    # from threading import get_ident
    # # 特殊的对象,不同线程操作它,操作的是线程自己的,不会出现并发安全问题
    # lqz = local()
    # def task(arg):
    #     # 对象.val = 1/2/3/4/5
    #     lqz.value = arg
    #     time.sleep(2)
    #     print(lqz.value)
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()



    # 自己写个local对象(low版本)

    # from threading import get_ident,Thread
    # import time
    # storage = {}
    # # {线程id号1:{key:value},线程id号2:{key:value},线程id号3:{key:value}}
    # def set(k,v):
    #     ident = get_ident() # 获取线程id号
    #     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(2)
    #     v = get('val')
    #     print(v)
    #
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()


    # 面向对象版本
    # from threading import get_ident,Thread
    # import time
    # class Local(object):
    #     storage = {}
    #     # {线程id号1: {key: value}, 线程id号2: {key: value}, 线程id号3: {key: value}}
    #     def set(self, k, v):
    #         ident = get_ident()
    #         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)
    #     v = obj.get('val')
    #     print(v)
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()


    # 面向对象版本,通过.取值,赋值
    # from threading import get_ident,Thread
    # import time
    # class Local(object):
    #     storage = {}
    #     ## {线程id号1: {key: value}, 线程id号2: {key: value}, 线程id号3: {key: value}}
    #     def __setattr__(self, k, v):
    #         ident = get_ident()
    #         if ident in Local.storage:
    #             Local.storage[ident][k] = v
    #         else:
    #             Local.storage[ident] = {k: v}
    #     def __getattr__(self, k):
    #         ident = get_ident()
    #         return Local.storage[ident][k]
    # obj = Local()
    # obj2 = Local() # 所有的local对象用的是同一个字典,不好
    # def task(arg):
    #     obj.val = arg
    #     print(obj.val)
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()


    # 不同local对象,使用自己的字典
    # from threading import get_ident,Thread
    # import time
    # class Local(object):
    #     def __init__(self):
    #         # self.storage={} 递归
    #         # setattr(self,'storage',{}) 递归
    #         #Local.__setattr__(self,'storage',{})
    #
    #         object.__setattr__(self,'storage',{})
    #
    #     def __setattr__(self, k, v):
    #         ident = get_ident()
    #         if ident in self.storage:
    #             self.storage[ident][k] = v
    #         else:
    #             self.storage[ident] = {k: v}
    #     def __getattr__(self, k):
    #         ident = get_ident()
    #         return self.storage[ident][k]
    # obj = Local()
    # def task(arg):
    #     obj.val = arg
    #     # obj.xxx = arg
    #     time.sleep(1)
    #     print(obj.val)
    # for i in range(10):
    #     t = Thread(target=task,args=(i,))
    #     t.start()


    # 多线程下可以使用,一旦加入协程,就不行了
    # 自定义一个兼容线程和协程的local对象
    try:
       from greenlet import getcurrent as get_ident

    except Exception as e:
       from threading import get_ident

    from threading import Thread
    import time
    class Local(object):
       def __init__(self):
           object.__setattr__(self,'storage',{})
       def __setattr__(self, k, v):
           ident = get_ident()
           if ident in self.storage:
               self.storage[ident][k] = v
           else:
               self.storage[ident] = {k: v}

           # try:
           #     storage[ident][name] = value
           # except KeyError:
           #     storage[ident] = {name: value}


       def __getattr__(self, k):
           ident = get_ident()
           return self.storage[ident][k]
    obj = Local()
    def task(arg):
       obj.val = arg
       # obj.xxx = arg
       print(obj.storage)
       print(obj.val)
    for i in range(10):
       t = Thread(target=task,args=(i,))
       t.start()

    4 偏函数

    from functools import partial  # 偏函数


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

    add=partial(add,2) # add是一个偏函数了,提前传值

    print(add)
    # print(add(3,4))
    print(add(2,3,4))
    # print(add(2,3,4))
  • 相关阅读:
    structs2---OGNL表达式
    六种获取配置properties文件的方法
    java poi导出Excel 总结
    Linux中发布项目的一些命令笔记
    JavaScript 闭包
    常见数据库连接方式
    Docker(五):镜像
    Docker(四):docker的安装
    Ubuntu命令
    Docker(三):Docker的基本概念
  • 原文地址:https://www.cnblogs.com/usherwang/p/14470929.html
Copyright © 2020-2023  润新知