• flask之上下文源码、flask-session、数据库连接池、flask-script等相关内容-143


    1 flask上下文源码分析(详见txt和图片)

    请求上下文执行流程(ctx):
    -0 flask项目一启动,有6个全局变量
    -_request_ctx_stack:LocalStack对象
    -_app_ctx_stack :LocalStack对象
    -request LocalProxy对象
    -session LocalProxy对象
    -1 请求来了 app.__call__()---->内部执行:self.wsgi_app(environ, start_response)
    -2 wsgi_app()
    -2.1 执行:ctx = self.request_context(environ):返回一个RequestContext对象,并且封装了request(当次请求的request对象),session
    -2.2 执行: ctx.push():RequestContext对象的push方法
    -2.2.1 push方法中中间位置有:_request_ctx_stack.push(self),self是ctx对象
    -2.2.2 去_request_ctx_stack对象的类中找push方法(LocalStack中找push方法)
    -2.2.3 push方法源码:
       def push(self, obj):
    #通过反射找self._local,在init实例化的时候生成的:self._local = Local()
    #Local()flask封装的支持线程和协程的local对象
    # 一开始取不到stack,返回None
    rv = getattr(self._local, "stack", None)
    if rv is None:
    #走到这,self._local.stack=[],rv=self._local.stack
    self._local.stack = rv = []
    # 把ctx放到了列表中
    #self._local={'线程id1':{'stack':[ctx,]},'线程id2':{'stack':[ctx,]},'线程id3':{'stack':[ctx,]}}
    rv.append(obj)
    return rv
    -3 如果在视图函数中使用request对象,比如:print(request)
    -3.1 会调用request对象的__str__方法,request类是:LocalProxy
    -3.2 LocalProxy中的__str__方法:lambda x: str(x._get_current_object())
    -3.2.1 内部执行self._get_current_object()
    -3.2.2 _get_current_object()方法的源码如下:
       def _get_current_object(self):
    if not hasattr(self.__local, "__release_local__"):
    #self.__local() 在init的时候,实例化的,在init中:object.__setattr__(self, "_LocalProxy__local", local)
    # 用了隐藏属性
    #self.__local 实例化该类的时候传入的local(偏函数的内存地址:partial(_lookup_req_object, "request"))
    #加括号返回,就会执行偏函数,也就是执行_lookup_req_object,不需要传参数了
    #这个地方的返回值就是request对象(当此请求的request,没有乱)
    return self.__local()
    try:
    return getattr(self.__local, self.__name__)
    except AttributeError:
    raise RuntimeError("no object bound to %s" % self.__name__)
    -3.2.3 _lookup_req_object函数源码如下:
    def _lookup_req_object(name):
    #name是'request'字符串
    #top方法是把第二步中放入的ctx取出来,因为都在一个线程内,当前取到的就是当次请求的ctx对象
    top = _request_ctx_stack.top
    if top is None:
    raise RuntimeError(_request_ctx_err_msg)
    #通过反射,去ctx中把request对象返回
    return getattr(top, name)
    -3.2.4 所以:print(request) 实质上是在打印当此请求的request对象的__str__
    -4 如果在视图函数中使用request对象,比如:print(request.method):实质上是取到当次请求的reuquest对象的method属性

    -5 最终,请求结束执行: ctx.auto_pop(error),把ctx移除掉

    其他的东西:
    -session:
    -请求来了opensession
    -ctx.push()---->也就是RequestContext类的push方法的最后的地方:
    if self.session is None:
    #self是ctx,ctx中有个app就是flask对象,   self.app.session_interface也就是它:SecureCookieSessionInterface()
    session_interface = self.app.session_interface
    self.session = session_interface.open_session(self.app, self.request)
    if self.session is None:
    #经过上面还是None的话,生成了个空session
    self.session = session_interface.make_null_session(self.app)
    -请求走了savesession
    -response = self.full_dispatch_request() 方法内部:执行了before_first_request,before_request,视图函数,after_request,savesession
    -self.full_dispatch_request()---->执行:self.finalize_request(rv)-----》self.process_response(response)----》最后:self.session_interface.save_session(self, ctx.session, response)
    -请求扩展相关
    before_first_request,before_request,after_request依次执行
    -flask有一个请求上下文,一个应用上下文
    -ctx:
    -是:RequestContext对象:封装了request和session
    -调用了:_request_ctx_stack.push(self)就是把:ctx放到了那个位置
    -app_ctx:
    -是:AppContext(self) 对象:封装了当前的app和g
    -调用 _app_ctx_stack.push(self) 就是把:app_ctx放到了那个位置
    -g是个什么鬼?
    专门用来存储用户信息的g对象,g的全称的为global
    g对象在一次请求中的所有的代码的地方,都是可以使用的


    -代理模式
    -request和session就是代理对象,用的就是代理模式

     

    -g是个什么鬼?
       专门用来存储用户信息的g对象,g的全称的为global
       g对象在一次请求中的所有的代码的地方,都是可以使用的 (当次请求中传递一些数据)
       
    -g对象和session的区别
    g对象只对当次请求有效(当此请求内有效)
       session:可以跨请求,该用户的多次请求中都可以使用

     

    2 flask-session的使用

    1 由于原生的flask中session是加密后放到了cookie中
    2 我们想保存到文件中,数据库中,redis(比较多)。。。
    3 借助于第三方:flask-session
    1 第一种使用方式
    from flask import Flask,session
    import redis
    from flask_session import RedisSessionInterface
    app = Flask(__name__)

    # 不需要指定
    # app.secret_key='dafasdf'

    conn=redis.Redis(host='127.0.0.1',port=6379)

    app.session_interface=RedisSessionInterface(conn,key_prefix='lqz')
    @app.route('/set_session')
    def set_session():
       session['name']='lqz'
       return 'session写入了,写了name=lqz'

    @app.route('/get_session')
    def get_session():
       # s=session['name']
       s=session.get('name','娶不到')
       return '获取到的session是'+s

    if __name__ == '__main__':
       app.run()
       
    2 第二种方式
    from flask_session import Session
    # 方式一
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
    app.config['SESSION_KEY_PREFIX']='lqz'
    # 方式二
    # app.config.from_object('settings.Pro')
    # 使用第三方插件,是一个通用方式
    Session(app) # 本质跟上面一样,只不过通过配置文件来处理,好处是后期只改配置文件,即可完成配置




    3 注意:设置session的过期时间,在配置文件中设置
    app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=7)

     

    3 数据库连接池

    https://www.cnblogs.com/liuqingzheng/articles/9006055.html
       
    1 传统方案存在的问题
    # 第一种方案,全局使用沟通一个curser会存在效率问题,安全性问题
    conn = pymysql.Connect(host='127.0.0.1', user='root', password="123", database='luffy', port=3306)
    curser = conn.cursor()

    # 第二种:不限制数据库的连接数,会导致连接数暴增
    conn = pymysql.Connect(host='127.0.0.1', user='root', password="123", database='luffy', port=3306)
    curser = conn.cursor()

    2 使用数据库连接池
    -pip3 install DButils
       -两种模式:
      第一种模式不用(为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭)
           第二种:创建一批连接到连接池,供所有线程共享使用

    3 使用步骤
    -第一步:新建sql_pool.py
       import pymysql
       # from DBUtils.PooledDB import PooledDB
       from dbutils.pooled_db import PooledDB
       POOL = PooledDB(
           creator=pymysql,  # 使用链接数据库的模块
           maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
           mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
           maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
           maxshared=3,  # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
           blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
           maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
           setsession=[],  # 开始会话前执行的命令列表。
           ping=0,
           # ping MySQL服务端,检查是否服务可用。
           host='127.0.0.1',
           port=3306,
           user='root',
           password='123',
           database='luffy',
           charset='utf8'
      )
       
       -第二步:使用
       from sql_pool import POOL
    conn = POOL.connection() # 从连接池种取一个链接(如果没有,阻塞在这)
       curser = conn.cursor()
       curser.execute('select * from luffy_order where id<2')
       res=curser.fetchall()
       print(res)

    4 flask-script

    1 django 运行项目  python manage.py runserver 
    2 借助于flask-script可以子定制命令
    pip3 install flask-script
       
    3 使用
    -自带一个runserver
       -自定制命令
       
       

    from flask import Flask
    from flask_script import Manager
    app = Flask(__name__)


    manager=Manager(app)


    # 自己定制命令
    @manager.command
    def custom(arg):
       """
      自定义命令
      python manage.py custom 123
      :param arg:
      :return:
      """
       print(arg)



    @manager.option('-n', '--name', dest='name')
    @manager.option('-u', '--url', dest='url')
    def cmd(name, url):
       """
      自定义命令(-n也可以写成--name)
      执行: python manage.py cmd -n lqz -u http://www.oldboyedu.com
      执行: python manage.py cmd --name lqz --url http://www.oldboyedu.com
      :param name:
      :param url:
      :return:
      """
       print(name, url)
    #有什么用?
    #把excel的数据导入数据库,定制个命令,去执行



    @app.route('/')
    def index():
       return '首页'

    if __name__ == '__main__':
       manager.run()
    #以后在执行,直接:python3 manage.py runserver
    #python3 manage.py runserver --help

     

     

     

  • 相关阅读:
    Linux 学习 step by step (1)
    ubuntu server nginx 安装与配置
    ubuntu server samba服务器配置
    iOS app集成支付宝支付流程及后台php订单签名处理
    mac 连接windows 共享内容
    linux 文件查找,which,whereis,locate,find
    ubuntu server vsftpd 虚拟用户及目录
    ubuntu server 安装 mantis bug tracker 中文配置
    ubuntu server vsftpd 匿名用户上传下载及目录设置
    linux 用户管理,用户权限管理,用户组管理
  • 原文地址:https://www.cnblogs.com/usherwang/p/14470936.html
Copyright © 2020-2023  润新知