zoukankan      html  css  js  c++  java
  • M1-Flask-Day1

    前情概要

       1.flask的基本使用

         - 配置

                      - 路由

                      - 视图

                      - 请求与响应相关

                      - 模板

       2.flask基于装饰器实现的路由

         - 基本操作

                      - functools

                      - 带参数的装饰器

         - 源码剖析

               3.flask-基于源码剖析session&特殊装饰器原理

    一.历史回顾

      1.装饰器原理

    def wapper(func):
        def inner(*args,**kwargs):
            print("执行装饰器逻辑")
            return func(*args,**kwargs)
        return inner
    
    """
    在程序执行从上到下加载,还未执行的时候 先执行如下两个步骤 1. 立即执行wapper函数,并将下面装饰的函数当做参数传递 2. 将wapper函数返回值获取,在index赋值 index = inner函数 """ @wapper def index(): print('函数内容') # 实际执行的 inner函数,inner函数内部调用原函数 index()

      2.functools

    import functools
    def wapper(func):
        @functools.wraps(func)
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    @wapper
    def index():
        print('index')
    
    @wapper
    def order():
        print("order")
    
    """
    默认不加functools会直接返回当前函数装饰器里inner的函数名字
    """
    print(index.__name__)
    print(order.__name__)
    """
    返回值
    index
    order
    """
    

      3.面向对象封装

    """
    面向对象封装
    """
    #将一些变量封装到一个类里进行统一调用
    class Foo(object):
        def __init__(self,age,name):
            self.age = age
            self.name = name
    
        def get_info(self):
            return self.name,self.age
        
        def __call__(self, *args, **kwargs):
            return self.name
    
    class Bar(object):
        def __init__(self,counter):
            self.counter = counter
            self.obj = Foo('18','guest') #这个也算是面向对象的组合,将用户封装到一个类里
    
    b1 = Bar(1)
    print(b1.obj.get_info())
    print(b1.obj()) #对象加()执行对象所在类的__call__方法
    

      4.加()会有几种表现形式-函数,类,方法,对象

    def f1():
        print('f1')
    
    class F2(object):
        pass
    
    class F3(object):
        def __init__(self):
            pass
    
        def ff3(self):
            print('ff3')
    
    class F4(object):
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('f4')
    def func(arg):
        """
        由于arg在函数中加括号,所以他只有4中表现形式:
            - 函数
            - 类
            - 方法
            - 对象
        :param arg:
        :return:
        """
        arg()
    
    # 1. 函数,内部执行函数
    func(f1)
    # 2. 类,内部执行__init__方法
    func(F2)
    
    # 3. 方法,obj.ff3,执行方法
    obj1 = F3()
    func(obj1.ff3)
    
    # F3.ff3(F3)类+方法的时候 方法就不是方法了而是函数 需要自行将self加进去
    
    # 4. 对象
    obj2 = F4()
    func(obj2)
    

      5.函数和方法的区别

    from types import MethodType,FunctionType
    class F3(object):
        def __init__(self):
            pass
    
        def ff3(self):
            print('ff3')
    
    # v1 = isinstance(F3.ff3,MethodType)
    # v2 = isinstance(F3.ff3,FunctionType)
    # print(v1,v2) # False,True
    
    obj = F3()
    v1 = isinstance(obj.ff3,MethodType)
    v2 = isinstance(obj.ff3,FunctionType)
    print(v1,v2) # True False 

      

    二、框架的本质

      1.基于socket实现

    import socket
    def main():
        # 创建老师
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost', 8000))
        sock.listen(5) #队列长度
    
        while True:
            # 老师等待 用户请求的到来
            connection, address = sock.accept()
            # 获取发送的内容:x有没有女朋友?
            # 获取发送的内容:xx 有没有女朋友?
            # 获取发送的内容:xxx有没有女朋友?
            # 获取发送的内容:xxxx有没有女朋友?
            buf = connection.recv(1024)
    
            # 根据请求URL的不同:
            # 回答:没有
            connection.send(b"HTTP/1.1 200 OK
    
    ")
            connection.send(b"No No No")
            # 关闭连接
            connection.close()
    if __name__ == '__main__':
        main()
    

      2.flask依赖werkzeug,django依赖wsgiref

    """
    from werkzeug.wrappers import Request, Response
    from werkzeug.serving import run_simple
    
    @Request.application
    def hello(request):
        return Response('Hello World!')
    
    if __name__ == '__main__':
        # 当请求打来之后,自动执行:hello()
        run_simple('localhost', 4000, hello)
    """
    
    
    from werkzeug.wrappers import Request, Response
    from werkzeug.serving import run_simple
    
    class Foo(object):
        def __call__(self, *args, **kwargs):
            return Response('Hello World!')
    
    if __name__ == '__main__':
        # 当请求打来之后,自动执行:hello()
        obj = Foo()
        run_simple('localhost', 4000, obj)
    

      3.快速使用flask搭建web

    from flask import Flask
    # 1. 实例化Flask对象
    app = Flask('xxxx')
    
    """
    1. 执行 app.route('/index')并获取返回值 xx
    2. 
        @xx
        def index():
            return 'Hello World'
    3. 执行 index = xx(index)
    本质: 
        {
            '/index': index
        }
    """
    @app.route('/index')
    def index():
        return 'Hello World'
    
    
    if __name__ == '__main__':
        app.run()

     三、Flask快速使用

    import functools
    from flask import Flask,render_template,request,redirect,session
    
    app = Flask('xxxx',template_folder="templates")
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    def auth(func):
        @functools.wraps(func)  #为了添加路由的时候函数名为被装饰的函数名
        def inner(*args,**kwargs):
            user_info = session.get('user_info')
            if not user_info:
                return redirect('/login')
            return func(*args,**kwargs)
        return inner
    """
    {
        /order: inner函数, name: order
        /index: inner函数, name: index
    }
    """
    
    @app.route('/order',methods=['GET'])  #认证的装饰器要放路由下面 先加载app.route
    @auth
    def order():
        user_info = session.get('user_info')
        if not user_info:
            return redirect('/login')
    
        return render_template('index.html')
    
    @app.route('/index',methods=['GET'])
    @auth
    def index():
        return render_template('index.html')
    
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method == "GET":
            return render_template('login.html')
        else:
            user = request.form.get('user')
            pwd = request.form.get('pwd')
            if user == 'alex' and pwd == '123':
                session['user_info'] = user
                return redirect('/index')
            # return render_template('login.html',msg = "用户名或密码错误",x =  123)
            return render_template('login.html',**{'msg':'用户名或密码错误'})
    
    @app.route('/logout',methods=['GET'])
    def logout():
        del session['user_info']
        return redirect('/login')
    if __name__ == '__main__':
        app.run()

     四、导入配置文件

      1.app.py

    #app.py
    from flask import Flask
    
    # 配置:模板/静态文件
    app = Flask('xxxx',template_folder="templates")
    # 配置:secret_key
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    
    # 导入配置文件
    app.config.from_object('settings.TestingConfig')
    
    @app.route('/index')
    def index():
        return "index"
    
    if __name__ == '__main__':
        app.run()
    

     2.settings.py

    class BaseConfig(object):
        DEBUG = False
        SESSION_REFRESH_EACH_REQUEST = True
    
    class ProConfig(BaseConfig):
        pass
    
    class DevConfig(BaseConfig):
        DEBUG = True
    
    class TestingConfig(BaseConfig):
        DEBUG = True

        flask配置文件详解:

    flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
        {
            'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
            'TESTING':                              False,                          是否开启测试模式
            'PROPAGATE_EXCEPTIONS':                 None,                          
            'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
            'SECRET_KEY':                           None,
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
            'USE_X_SENDFILE':                       False,
            'LOGGER_NAME':                          None,
            'LOGGER_HANDLER_POLICY':               'always',
            'SERVER_NAME':                          None,
            'APPLICATION_ROOT':                     None,
            'SESSION_COOKIE_NAME':                  'session',
            'SESSION_COOKIE_DOMAIN':                None,
            'SESSION_COOKIE_PATH':                  None,
            'SESSION_COOKIE_HTTPONLY':              True,
            'SESSION_COOKIE_SECURE':                False,
            'SESSION_REFRESH_EACH_REQUEST':         True,
            'MAX_CONTENT_LENGTH':                   None,
            'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
            'TRAP_BAD_REQUEST_ERRORS':              False,
            'TRAP_HTTP_EXCEPTIONS':                 False,
            'EXPLAIN_TEMPLATE_LOADING':             False,
            'PREFERRED_URL_SCHEME':                 'http',
            'JSON_AS_ASCII':                        True,
            'JSON_SORT_KEYS':                       True,
            'JSONIFY_PRETTYPRINT_REGULAR':          True,
            'JSONIFY_MIMETYPE':                     'application/json',
            'TEMPLATES_AUTO_RELOAD':                None,
        }
     
    方式一:
        app.config['DEBUG'] = True
     
        PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
     
    方式二:
        app.config.from_pyfile("python文件名称")
            如:
                settings.py
                    DEBUG = True
     
                app.config.from_pyfile("settings.py")
     
        app.config.from_envvar("环境变量名称")
            环境变量的值为python文件名称名称,内部调用from_pyfile方法
     
     
        app.config.from_json("json文件名称")
            JSON文件名称,必须是json格式,因为内部会执行json.loads
     
        app.config.from_mapping({'DEBUG':True})
            字典格式
     
        app.config.from_object("python类或类的路径")
     
            app.config.from_object('pro_flask.settings.TestingConfig')
     
            settings.py
     
                class Config(object):
                    DEBUG = False
                    TESTING = False
                    DATABASE_URI = 'sqlite://:memory:'
     
                class ProductionConfig(Config):
                    DATABASE_URI = 'mysql://user@localhost/foo'
     
                class DevelopmentConfig(Config):
                    DEBUG = True
     
                class TestingConfig(Config):
                    TESTING = True
     
            PS: 从sys.path中已经存在路径开始写
         
     
        PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
    

      

     五、给字符串路径自动找到指定类并执行

      importlib + 反射

    import settings
    import importlib
    def send_notify():
        for path in settings.NOTIFY_LIST:
            # 'notify.email.Email',
            # 'notify.msg.Msg',
            module_path,cls_name = path.rsplit('.',maxsplit=1) #右排序 取一个
            # m = importlib.import_module("notify.email") # import  notify.email
            m = importlib.import_module(module_path)
            cls = getattr(m,cls_name)
            obj = cls()
            obj.send()
    
    """
    settings.py
    NOTIFY_LIST = [
        'notify.email.Email',
        'notify.wechat.Wechat',
        'notify.msg.Msg',
    """
    
    """
    run.py
    from notify import send_notify
    
    def run():
        send_notify()
    
    
    if __name__ == '__main__':
        run()
    """ 

    六、路由系统  

      1.cbv与fbv的使用方法:fbv可以种app.route的方法添加

    #fbv可以用装饰器
    @app.route('/index')
    def index():
        return "index"
    
    
    def order():
        return 'Order'
    app.add_url_rule('/order', None, order)
    
    
    class TestView(views.View):
        methods = ['GET']
        def dispatch_request(self):
            return 'test!'
    
    app.add_url_rule('/test', view_func=TestView.as_view(name='test'))  # name=endpoint
    # app.add_url_rule('/test', view_func=view函数)  # name=endpoint
    

      2.CBV加装饰器和methods方法

    def auth(func):
        def inner(*args, **kwargs):
            print('before')
            result = func(*args, **kwargs)
            print('after')
            return result
        return inner
    
    class X1View(views.MethodView):
        methods = ['GET','POST']
        decorators = [auth, ]
    
        def get(self):
            return 'x1.GET'
    
        def post(self):
            return 'x1.POST'
    
    
    app.add_url_rule('/x1', view_func=X1View.as_view(name='x1'))  #name=endpoint

           3.执行@app.route('/index')

    """
    生成类似dict的形式
    {
        '/index': index函数
    }
    1. decorator = app.route('/index')
    2. 
        @decorator
        def index():
            return "index"
    3. decorator(index)
    """
    """
    Map() = [
        Rule(rule=/index/ endpoint=None  view_func=函数),
    ]
    """
    

      4.路由系统源码剖析

    route函数

    def route(self, rule, **options):
    	'''
    	rule为url 例子rule='/index'
    	'''
    
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            '''
            rule为/index,f为函数名
            '''
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator
    	
    

      

    """
    这段说明 如果endpoint为空,类似django的url里的name字段,就使用当前函数的__name__做为endpoint
    """
    
    if endpoint is None:
    endpoint = _endpoint_from_view_func(view_func)
    """
    将options里封装了反向生成url
    """
    options['endpoint'] = endpoint
    
    def _endpoint_from_view_func(view_func):
    
    	assert view_func is not None, 'expected view func if endpoint ' 
                          'is not provided.'
    	return view_func.__name__
    
     def execute(app):
        application_iter = app(environ, start_response) #对象加()执行__call__方法
        try:
            for data in application_iter:
                write(data)
            if not headers_sent:
                write(b'')
        finally:
            if hasattr(application_iter, 'close'):
                application_iter.close()
            application_iter = None
    
    try:
        execute(self.server.app) #self.server.app 应该为Flask对象
    

      可以看到 application_iter = app(environ, start_response) 就是调用代码获取结果的地方。

      要调用 app 实例,那么它就需要定义了 __call__ 方法,我们找到 flask.app:Flask 对应的内容:

      

      

    def auth(func):
                def inner(*args, **kwargs):
                    print('before')
                    result = func(*args, **kwargs)
                    print('after')
                    return result
    
            return inner
    
            @app.route('/index.html',methods=['GET','POST'],endpoint='index')
            @auth
            def index():
                return 'Index'def index():
                return "Index"
    
            self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
            or
            app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
            app.view_functions['index'] = index
    
    
            或
            def auth(func):
                def inner(*args, **kwargs):
                    print('before')
                    result = func(*args, **kwargs)
                    print('after')
                    return result
    
            return inner
    
            class IndexView(views.View):
                methods = ['GET']
                decorators = [auth, ]
    
                def dispatch_request(self):
                    print('Index')
                    return 'Index!'
    
            app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    class IndexView(views.MethodView):
                methods = ['GET']
                decorators = [auth, ]
    
                def get(self):
                    return 'Index.GET'
    
                def post(self):
                    return 'Index.POST'
    
    
            app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    
    
    
    
            @app.route和app.add_url_rule参数:
                rule,                       URL规则
                view_func,                  视图函数名称
                defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
                endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
                methods=None,               允许的请求方式,如:["GET","POST"]
                
    
                strict_slashes=None,        对URL最后的 / 符号是否严格要求,
                                            如:
                                                @app.route('/index',strict_slashes=False),
                                                    访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
                                                @app.route('/index',strict_slashes=True)
                                                    仅访问 http://www.xx.com/index 
                redirect_to=None,           重定向到指定地址
                                            如:
                                                @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
                                                或
                                                def func(adapter, nid):
                                                    return "/home/888"
                                                @app.route('/index/<int:nid>', redirect_to=func)
                subdomain=None,             子域名访问
                                                    from flask import Flask, views, url_for
    
                                                    app = Flask(import_name=__name__)
                                                    app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
    
    
                                                    @app.route("/", subdomain="admin")
                                                    def static_index():
                                                        """Flask supports static subdomains
                                                        This is available at static.your-domain.tld"""
                                                        return "static.your-domain.tld"
    
    
                                                    @app.route("/dynamic", subdomain="<username>")
                                                    def username_index(username):
                                                        """Dynamic subdomains are also supported
                                                        Try going to user1.your-domain.tld/dynamic"""
                                                        return username + ".your-domain.tld"
    
    
                                                    if __name__ == '__main__':
                                                        app.run()
            
    注册路由原理
    from flask import Flask, views, url_for
                from werkzeug.routing import BaseConverter
    
                app = Flask(import_name=__name__)
    
    
                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
    
                # 添加到flask中
                app.url_map.converters['regex'] = RegexConverter
    
    
                @app.route('/index/<regex("d+"):nid>')
                def index(nid):
                    print(url_for('index', nid='888'))
                    return 'Index'
    
    
                if __name__ == '__main__':
                    app.run()
    
    b. 自定制正则路由匹配
    自定制正则路由匹配
    @app.route('/user/<username>')
    @app.route('/post/<int:post_id>')
    @app.route('/post/<float:post_id>')
    @app.route('/post/<path:path>')
    @app.route('/login', methods=['GET', 'POST'])
    路由注册方法

     七、Flask特殊装饰器

    from flask import Flask,render_template,request,redirect,session
    
    app = Flask('xxxx',template_folder="templates")
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    
    
    @app.before_request #类似于django的middleware
    def bf():
        if request.path == '/login':
            return None
        user_info = session.get('user_info')
        if not user_info:
            return redirect('/login')
    
    @app.route('/order',methods=['GET'])
    def order():
        return "order"
    
    @app.route('/index',methods=['GET'])
    def index():
        return "index"
    
    @app.route('/logout',methods=['GET'])
    def logout():
        del session['user_info']
        return redirect('/login')
    
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method == "GET":
            return render_template('login.html')
        else:
            user = request.form.get('user')
            pwd = request.form.get('pwd')
            if user == 'alex' and pwd == '123':
                session['user_info'] = user
                return redirect('/index')
            # return render_template('login.html',msg = "用户名或密码错误",x =  123)
            return render_template('login.html',**{'msg':'用户名或密码错误'})
    
    if __name__ == '__main__':
        app.run()
    用flask_middleware实现用户登录认证

      请求之前:@app.before_request

    def before_request(self, f):
    
        #self.before_request_funcs = {}
        #结果返回 {None: [bf1,bf2]}
        # setdefault(None, [])会返回{None:[]}
    self.before_request_funcs.setdefault(None, []).append(f) return f

      请求之后:

    def after_request(self, f):
    	#{None:[af1,af2]}
        self.after_request_funcs.setdefault(None, []).append(f)
        return f

    八、模版使用

    import functools
    from flask import Flask,render_template,request,redirect,session,Markup
    
    app = Flask('xxxx',template_folder="templates")
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    
    @app.template_global()
    
    def sb(a1, a2):
        return a1 + a2
    
    
    @app.template_filter()
    """
    类似django的filter
    """
    def db(a1, a2, a3):
        return a1 + a2 + a3
    
    
    
    def fffff(value):
        return Markup("<input type='text' value='%s' />" %(value,))  #与django的make_safe一样
    
    @app.route('/index',methods=['GET'])
    def index():
        context = {
            'k1': 'v1',
            'k2': [11,22,33],
            'k3':{
                'name':'oldboy',
                'age': 56
            },
            'k4':fffff
        }
        return render_template('index.html',**context)
    
    @app.route('/order',methods=['GET'])
    def order():
        return render_template('order.html')
    
    if __name__ == '__main__':
        app.run()
    1.模版基本使用
    {% extends "layout.html" %} #继承
    
    
    {% block content %}
        <h1>欢迎进入系统</h1>
    
        {% include 'xxx.html'%} #类似django的include_tag
        {% include 'xxx.html'%}
        {% include 'xxx.html'%}
    
        <p>{{k1}}</p>
        <p>{{k2.0}}  {{k2[0]}}</p>
        <ul>
            {% for item in k2 %}
                <li>{{item}}</li>
            {% endfor %}
        </ul>
    
        <p>{{k3.name}} {{k3['name']}} {{k3.get('name')}} </p> #可以用get,这样可以设置取不到为空不会出现异常
        <ul>
            {% for item in k3.keys() %}
                <li>{{item}}</li>
            {% endfor %}
        </ul>
        <ul>
            {% for item in k3.values() %}
                <li>{{item}}</li>
            {% endfor %}
        </ul>
        <ul>
            {% for k,v in k3.items() %}
                {% if v == 'oldboy'%}
                    <li>老男人:{{k}} {{v}}</li>
                {% else %}
                    <li>{{k}} {{v}}</li>
                {% endif %}
            {% endfor %}
        </ul>
        <h1>函数: {{k4('123')}}</h1> #可以执行函数返回
        <h1>全局函数: {{sb(1,2)}}  {{ 1|db(2,3)}}</h1> #全局生效,类似于django的filter和simple_tag
    {% endblock %}
    2.html中模版的使用
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div style="height: 48px;">
            头部内容
        </div>
        <div>
            {% block content %} {% endblock %}
        </div>
    
        <div style="height: 48px;">
            底部内容
        </div>
    </body>
    </html>
    3.模版基类
    {% extends "layout.html" %}
    
    
    {% block content %}
        <h1>订单列表</h1>
    
    {% endblock %}
    4.模版继承

    九、Flask-session源码剖析

       1.特殊的字典,当前类继承dict就具有dict的特性

    class MyDict(dict):
        def on_update(self):
            pass
    
    v2 = MyDict()
    v2['k1'] = 'v1'
    print(v2,type(v2))
    v3 = dict(v2)
    print(v3,type(v3))
    

      2.flask请求进来先执行Flask类的__call__方法 将environ和start_response传入(请求相关的信息)

     def __call__(self, environ, start_response):
         """Shortcut for :attr:`wsgi_app`."""
         return self.wsgi_app(environ, start_response)
    

        3. ctx = self.request_context(environ)将请求相关的数据传入Flask类的request_context方法,request_context方法实例化RequestContext,执行__init__

    def request_context(self, environ):
    	#实例化RequestContext 执行__init__
        return RequestContext(self, environ)
    

       4.RequestContext的构造方法中,再次实例化了request = app.request_class(environ) 一个request类将请求相关的数据封装到request类中,执行request的__init__方法

    def __init__(self, app, environ, request=None):
        self.app = app
        if request is None:
            request = app.request_class(environ) #封装
        self.request = request
        self.url_adapter = app.create_url_adapter(self.request)
        self.flashes = None
        self.session = None
    
        # Request contexts can be pushed multiple times and interleaved with
        # other request contexts.  Now only if the last level is popped we
        # get rid of them.  Additionally if an application context is missing
        # one is created implicitly so for each level we add this information
        self._implicit_app_ctx_stack = []
    
        # indicator if the context was preserved.  Next time another context
        # is pushed the preserved context is popped.
        self.preserved = False
    
        # remembers the exception for pop if there is one in case the context
        # preservation kicks in.
        self._preserved_exc = None
    

      5.通过ctx.push()=Request_Context.push()执行session的操作

    def push(self):
    
        top = _request_ctx_stack.top
        if top is not None and top.preserved:
            top.pop(top._preserved_exc)
    
        app_ctx = _app_ctx_stack.top
        if app_ctx is None or app_ctx.app != self.app:
            app_ctx = self.app.app_context()
            app_ctx.push()
            self._implicit_app_ctx_stack.append(app_ctx)
        else:
            self._implicit_app_ctx_stack.append(None)
    
        if hasattr(sys, 'exc_clear'):
            sys.exc_clear()
    
        _request_ctx_stack.push(self)
    
        #此处操作session
        self.session = self.app.open_session(self.request)
        if self.session is None:
                self.session = self.app.make_null_session()
    

       6.open_session执行Flask类的 self.session_interface.open_session(self, request)

        Flask的 session_interface = SecureCookieSessionInterface()

        相当于执行了 SecureCookieSessionInterface类里的 open_session 方法

    def open_session(self, app, request):
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        val = request.cookies.get(app.session_cookie_name)
        if not val:
            return self.session_class()
            “”“
            	self.session_class() = SecureCookieSession() SecureCookieSession继承了dict
            ”“”
        max_age = total_seconds(app.permanent_session_lifetime)
        try:
            data = s.loads(val, max_age=max_age) #通过sercet_key进行编码
            return self.session_class(data)
        except BadSignature:
            return self.session_class()
    

      

  • 相关阅读:
    LeetCode 1245. Tree Diameter
    LeetCode 1152. Analyze User Website Visit Pattern
    LeetCode 1223. Dice Roll Simulation
    LeetCode 912. Sort an Array
    LeetCode 993. Cousins in Binary Tree
    LeetCode 1047. Remove All Adjacent Duplicates In String
    LeetCode 390. Elimination Game
    LeetCode 1209. Remove All Adjacent Duplicates in String II
    LeetCode 797. All Paths From Source to Target
    LeetCode 1029. Two City Scheduling
  • 原文地址:https://www.cnblogs.com/liujiliang/p/8854932.html
Copyright © 2011-2022 走看看