zoukankan      html  css  js  c++  java
  • DAY 95 flask04

    1 python的web框架
    -django框架,同步框架,3.x以后,加入了异步,websocket
      -1.x对websocket支持比较差
           -2.x channels
           -3.x 可以使用channels,原生支持,asgi协议
      -flask,同步框架
      -orm没有:sqlalchemy
           -session,redis,异步,信号(第三方支持),forms,
       -web.py
       -tornado:异步,老牌,python2上
       -sanic: aiomysql  aioredis,异步orm框架
       -fastapi:
           
       -websocket:应用层协议,为了解决http协议存在的问题,长连接,服务端主动向客户端推送消息
       
    2 flask框架
    -介绍
       -基本使用
       -登录显示用户信息案例
       -配置文件(使用类方式)
       -路由系统(基本使用和本质)
       -cbv分析
       -模板语法
       -请求响应
       -session(源码:SecureCookieSessionInterface)
       -闪现:flash
       -请求扩展
      -before_request
           -after_request
           -before_first_request
           -teardown_request
           -errorhandler
           -template_global
           -template_filter
       -中间件
      -服务器中间件
           -数据库中间(分库分表,读写分离 mycat)
           -消息队列中间件(redis,rabbitmq(保证数据准确性),kafka(吞吐量)...)
       -蓝图
       -请求上下文分析
       
       
    服务和服务之间调用
    -http符合restful规范
       -rpc(远程过程调用):rpc框架:grpc...,底层socket,也用http
       -消息队列:
       
       
       
    django内置的app中:management
    -django自定制命令
       python mangae.py initdb (把在项目路径下的sql文件导入数据库)

     

    flask上下文源码回顾

    请求上下文执行流程(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放到了那个位置

     

    1 flask-session


    # 使用方式一
    from flask_session import RedisSessionInterface,FileSystemSessionInterface,MemcachedSessionInterface
    # from redis import Redis
    # conn = Redis()
    app.session_interface = RedisSessionInterface(redis=conn, key_prefix='flask_xx')


    # 使用方式二
    from redis import Redis
    from flask.ext.session import Session

    # 如果在配置类中这么写
    # SESSION_TYPE='redis'
    # SESSION_REDIS=Redis(host='127.0.0.1',port='6379')

    # 如果没有配置类,需要这么写
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
    app.config['SESSION_KEY_PREFIX'] = 'dasfasdfas'
    Session(app)




    # 1 关闭浏览器,session失效--》permanent=False
    app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False)

    # 2 session的过期时间是多少?(一般7天)
    -timedelta(days=31)
       -flask:31天
       -django:14天
       -drf:token默认7天

    2 数据库连接池

    https://www.cnblogs.com/liuqingzheng/articles/9006055.html
       
       
    #1 pymysql操作数据库
    -如果conn,cursor是全局变量,会出现数据混乱
       -如果conn,cursor在视图函数中,会导致多个请求会有多个数据库链接(django就是这样)
     

    # 2 在flask中引入数据库连接池
    -pip3 install DBUtils

    # 3 使用步骤
    -第一步,建立一个py文件,创建池对象
       import pymysql
       # 老版本
       # from DBUtils.PooledDB import PooledDB
       # 新版本
       from dbutils.pooled_db import PooledDB
       # 池对象
       POOL = PooledDB(
           creator=pymysql,  # 使用链接数据库的模块
           maxconnections=10,  # 连接池允许的最大连接数,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='test',
           charset='utf8'
      )
       
      -第二步:在视图函数中使用
    @app.route('/')
       def index():
           conn = POOL.connection()
           cursor = conn.cursor()
           cursor.execute('select * from employee')
           result = cursor.fetchall()
           print(result)
           return 'hello'

     

    3 wtforms(了解,flask版forms)

    1 字段校验
    form = RegisterForm(formdata=request.form)
    if form.validate():
    print('用户提交数据通过格式验证,提交的值为:', form.data)
    else:
       print(form.errors)
       return render_template('register.html', form=form)
    2 模板渲染
    <form method="post" novalidate style="padding:0 50px">
      {% for field in form %}
       <p>{{field.label}}: {{field}} {{field.errors[0]}}</p>
      {% endfor %}
       <input type="submit" value="提交">
    </form>
    3 渲染错误信息

    4 信号

    #https://www.cnblogs.com/liuqingzheng/articles/9803403.html

    # Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为


    # 内置信号的使用
    ## 给内置信号绑定一个函数
    def request_finish_01(*args, **kwargs):
       print('请求走了')
       print(args)
       print(kwargs)
    signals.request_finished.connect(request_finish_01)


    # 自定义信号的使用
    ## 第0步:定义信号(内置信号,不需要定义)

    from flask.signals import _signals
    # 定义了一个xxx信号
    xxx = _signals.signal('xxx')

    ## 第一步:定义一个函数,绑定给信号(内置信号的其中一个)
    def my_sig(*args, **kwargs):
       print('xxxx')
       print(args)
       print(kwargs)
    xxx.connect(my_sig)

    ## 第二步:触发信号(由于是内置信号,会自动触发,只要触发信号就会执行这个函数)
    xxx.send()
  • 相关阅读:
    Pull Request
    选择器
    常见HTTP状态码
    286. Walls and Gates
    200. Number of Islands
    1. Two Sum
    名片管理系统(python实现)
    k近邻算法(简单版)
    基数排序
    递归算法的调试
  • 原文地址:https://www.cnblogs.com/DEJAVU888/p/14894189.html
Copyright © 2011-2022 走看看