Flask进阶(路由视图,session,蓝图,上下文管理)

1. 路由+视图
    a. 路由设置的两种方式:
        @app.route('/xxx')
            def index():
                return "index"

        
        def index():
            return "index"
        app.add_url_rule("/xxx",None,index)
        
        注意事项:
            - 不用让endpoint重名
            - 如果重名函数也一定要相同。
    b. 参数
        rule,                       URL规则
        view_func,                  视图函数名称
        endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
        methods=None,               允许的请求方式,如:["GET","POST"]
        strict_slashes=None,        对URL最后的 / 符号是否严格要求,
        redirect_to=None,           重定向到指定地址

        defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
        subdomain=None,             子域名访问
    c. CBV
        import functools
        from flask import Flask,views
        app = Flask(__name__)


        def wrapper(func):
            @functools.wraps(func)
            def inner(*args,**kwargs):
                return func(*args,**kwargs)

            return inner



        class UserView(views.MethodView):
            methods = ['GET']
            decorators = [wrapper,]

            def get(self,*args,**kwargs):
                return 'GET'

            def post(self,*args,**kwargs):
                return 'POST'

        app.add_url_rule('/user',None,UserView.as_view('uuuu'))

        if __name__ == '__main__':
            app.run()
    d. 自定义正则
        from flask import Flask,url_for

        app = Flask(__name__)

        # 步骤一:定制类
        from werkzeug.routing import BaseConverter
        class RegexConverter(BaseConverter):
            """
            自定义URL匹配正则表达式
            """

            def __init__(self, map, regex):
                super(RegexConverter, self).__init__(map)
                self.regex = regex

            def to_python(self, value):
                """
                路由匹配时,匹配成功后传递给视图函数中参数的值
                :param value:
                :return:
                """
                return int(value)

            def to_url(self, value):
                """
                使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
                :param value:
                :return:
                """
                val = super(RegexConverter, self).to_url(value)
                return val

        # 步骤二:添加到转换器
        app.url_map.converters['reg'] = RegexConverter

        """
        1. 用户发送请求
        2. flask内部进行正则匹配
        3. 调用to_python(正则匹配的结果)方法
        4. to_python方法的返回值会交给视图函数的参数

        """

        # 步骤三:使用自定义正则
        @app.route('/index/<reg("\d+"):nid>')
        def index(nid):
            print(nid,type(nid))

            print(url_for('index',nid=987))
            return "index"

        if __name__ == '__main__':
            app.run()
    
2. session实现原理(源码)
    - 请求到来之后wsgi会触发__call__方法,由__call__方法再次调用wsgi_app方法
        - 在wsgi_app方法中:
            - 首先将 请求相关+空session 封装到一个RequestContext对象中,即:ctx。
            - 将ctx交给LocalStack对象,再由LocalStack将ctx添加到Local中,Local结构:
                __storage__ = {
                    1231:{stack:[ctx,] }
                }
            - 根据请求中的cookie中提取名称为sessionid对应的值,对cookie进行加密+反序列化,再次赋值给ctx中的session
            
            -> 视图函数
            
            - 把session中的数据再次写入到cookie中。
            - 将ctx删除
        - 结果返回给用户浏览器
        - 断开socket连接
    
3. 蓝图
    目标:给开发者提供目录结构
    
    其他:
        - 自定义模板、静态文件
        - 某一类url添加前缀
        - 给一类url添加before_request
    
4. threading.local【和flask无任何关系】
    作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。
        import threading
        from threading import local
        import time

        obj = local()


        def task(i):
            obj.xxxxx = i
            time.sleep(2)
            print(obj.xxxxx,i)

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

    问题:
        - 如何获取一个线程的唯一标记? threading.get_ident()
        - 根据字典自定义一个类似于threading.local功能?
            import time
            import threading

            DIC = {}

            def task(i):
                ident = threading.get_ident()
                if ident in DIC:
                    DIC[ident]['xxxxx'] = i
                else:
                    DIC[ident] = {'xxxxx':i }
                time.sleep(2)

                print(DIC[ident]['xxxxx'],i)

            for i in range(10):
                t = threading.Thread(target=task,args=(i,))
                t.start()
            
        - 根据字典自定义一个为每个协程开辟空间进行存取数据。
        
            import time
            import threading
            import greenlet

            DIC = {}

            def task(i):
                
                # ident = threading.get_ident()
                ident = greenlet.getcurrent()
                if ident in DIC:
                    DIC[ident]['xxxxx'] = i
                else:
                    DIC[ident] = {'xxxxx':i }
                time.sleep(2)

                print(DIC[ident]['xxxxx'],i)

            for i in range(10):
                t = threading.Thread(target=task,args=(i,))
                t.start()
        
        - 通过getattr/setattr 构造出来 threading.local的加强版(协程)
            import time
            import threading
            try:
                import greenlet
                get_ident =  greenlet.getcurrent
            except Exception as e:
                get_ident = threading.get_ident

            class Local(object):
                DIC = {}

                def __getattr__(self, item):
                    ident = get_ident()
                    if ident in self.DIC:
                        return self.DIC[ident].get(item)
                    return None

                def __setattr__(self, key, value):
                    ident = get_ident()
                    if ident in self.DIC:
                        self.DIC[ident][key] = value
                    else:
                        self.DIC[ident] = {key:value}
                    

            obj = Local()

            def task(i):
                obj.xxxxx = i
                time.sleep(2)
                print(obj.xxxxx,i)

            for i in range(10):
                t = threading.Thread(target=task,args=(i,))
                t.start()
        
5. 上下文管理(第一次)
    请求到来时候:
        # ctx = RequestContext(self, environ) # self是app对象,environ请求相关的原始数据
        # ctx.request = Request(environ)
        # ctx.session = None
        
        # 将包含了request/session的ctx对象放到“空调”
            {
                1232:{ctx:ctx对象}
                1231:{ctx:ctx对象}
                1211:{ctx:ctx对象}
                1111:{ctx:ctx对象}
                1261:{ctx:ctx对象}
            }
            
    视图函数:
        from flask import reuqest,session
        
        request.method
        
        
    请求结束:
        根据当前线程的唯一标记,将“空调”上的数据移除。

猜你喜欢

转载自www.cnblogs.com/l-jie-n/p/10089388.html