zoukankan      html  css  js  c++  java
  • 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

     

     

     

  • 相关阅读:
    😉P03 Go 基础知识😉
    😎P03 DB 数据库的约束条件、表关系、修改表语法以及复制表😎
    😉P02 Go 快速上手😉
    C# NPOI导出Excel横向纵向显示
    C# 批量上传文件 添加图片水印
    C# 压缩ZIP
    SQL Server循环插入100000条数据
    C# 特殊字符过滤拦截
    C# 导入Excel到数据库
    C# 实现批量删除功能
  • 原文地址:https://www.cnblogs.com/usherwang/p/14470936.html
Copyright © 2011-2022 走看看