• python3-开发进阶Flask的基础(2)


    知识回顾

    1、django 和flask区别?

      最大的不同就是django请求相关的数据,通过参数一个一个传递过去的,而flask就是先把放在某个地方,然后去取,这个东西叫上下文管理

    2、什么是wsgi?

      web服务网关接口,wsgi就是一个协议和规范,实现该协议的模块:

      -wsgiref

      -werkzeug

      实现其协议的模块本质上就是socket服务端用于接收用户请求,并处理,

      一般web框架基于wsgi实现,这样实现关注点分离(通俗的说业务相关的,交给框架)

    from werkzeug.wrappers import  Response
    from werkzeug.serving import run_simple
    
    def run_sever(environ,start_response):
        response=Response('duoduo')   # 封装一下
        return response(environ,start_response)
    
    if __name__ == '__main__':
        run_simple('127.0.0.1',8000,run_sever)

    3、flask提供的功能

    配置文件 

      所有配置文件都在flask的对象.config中

      flask的对象.config.from_object('引入类的路径')   小写也是生效的

      应用: importlib 、getattr

        django中间件

        rest framework全局配置

    session

      加密后放置在用户浏览器的cookie中

      流程:

        请求到来--------》视图函数---------》请求结束

      配置文件   生命周期31天   加密设置

    路由

      带参数的装饰器,自定义装饰器放下面

      常用url,methods,endpoint   反向 url_for

    视图

      FBV

    特殊装饰器

      before_first_request

      before_request

      after_request

      template_global()

      template_filter()

      errorhandler(404)

    请求和响应

      请求:request

      响应:四种 字符串、render_template(模板)、redirect、jsonify (序列化)

      加响应头就make_response

    一、路由和视图

    from flask import Flask
    duo=Flask(__name__)
    
    @duo.route('/index')
    def index():
        print('index')
        return 'Index'
    
    if __name__ == '__main__':
        duo.run()

    我们今天开看看route的源码是什么样子的:

    先不看中间的,发现定义阶段只是返回了 函数decorator的名字

    1、限制性  decorator=duo.route('/index')

    2、@decorator   这就和装饰器的原理一样,执行的话就把被装饰的函数名字传进去

    3、上图中的f就是index函数,而rule就是(’/index‘)

    这里就可以看出这个装饰器实质上就是:

    duo.add_url_rule('/index', None, index)

    我们注释掉装饰器,就用这一句代码跑跑看,脚本跑起来没问题!

    我们继续看。add_url_rule里面的源码:

     验证了之前说过的为什么endpoint默认情况等于函数名

     获得参数都放到类似一个类,点开看看

     

    果然是一个类

     

     将路有关系添加到所有路由关系映射表

     

     

    总结:

    尽量不要让endpoint重名,如果重名函数一定要相同

    参数:

    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,             子域名访问

    CBV:

    from flask import Flask,views
    import functools
    def wrapper(func):
        @functools.wraps(func)
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    duo=Flask(__name__)
    
    class UserView(views.MethodView):
        methods = ['GET']  #只允许GET请求
        decorators = [wrapper,]   #加上要执行的装饰器的名字
        def get(self,*args,**kwargs):
    
            return 'GET'
    
        def post(self,*args,**kwargs):
            return 'POST'
    
    duo.add_url_rule('/user',None,UserView.as_view('uuuu'))
    
    if __name__ == '__main__':
        duo.run()

     基本上大同小异

    自定义正则:

    from  flask import Flask,url_for
    duo=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   #完全可以不写
    
    #步骤二:添加到转换器
    duo.url_map.converters['reg']=RegexConverter
    
    '''
    1、用户发送请求
    2、flask内部进行正则匹配
    3、调用to_python(正则匹配的结果)方法
    4、to_python的返回值会交给视图函数的参数'''
    
    #步骤三:使用自定义正则
    @duo.route('/index/<reg("d+"):nid>')
    def index(nid):
        print(nid,type(nid))
        print(url_for('index',nid=1))
        return 'index'
    
    if __name__ == '__main__':
        duo.run()

    二、session实现原理(源码)

    flask 

     

    下面我们来一行行来验证上面猜想的:

    self 是Flask的对象duo,environ请求相关的原始数据

     

     三、蓝图

    目标:给开发者提供一个目录结构

    1、首先创建一个和项目一样名字的文件夹,在文件夹中的__init__.py,先定义一个创建对象的函数

    from flask import Flask
    
    def create_app():
        duo=Flask(__name__)
        return duo

    2、在项目一样名字的文件夹下,创建视图文件夹,在里面单独创建需求的功能视图

    from flask import Blueprint
    
    uc=Blueprint('ac',__name__)
    @uc.route('/index/')
    def index():
        return 'Index'

    3、建立他们之间的关系,在__init__导入生成的对象 uc,最后注册进去

    from flask import Flask
    from .views.user import uc
    
    
    def create_app():
        duo=Flask(__name__)
        duo.register_blueprint(uc,url_prefix='/duoduuo')  #url_prefix适用版本控制   
        return duo
    
    
    #最后再写一个运行的脚本,

    其他的功能:

    自定义模板、静态文件

    某一类url添加前缀

    某一类url添加before_request

    四、threading.local(和flask无任何关系)

    先看一个简单事例:

    import threading
    import time
    v=0
    def task(i):
        global v
        v=i
        time.sleep(1)
        print(v)
    
    for i in range(10):
        t=threading.Thread(target=task,args=(i,))
        t.start()
    
    
    #结果都是9,最后一个修改覆盖所有,解决方法加锁

    看一种解决方案:

    import threading
    from threading import local
    #为每给线程创建一个独立空间来修改数据,使得线程对自己的空间中的数据进行操作(数据隔离)
    import time
    
    obj=local()
    
    def task(i):
        obj.duo=i
        time.sleep(1)
        print(obj.duo,i)
    
    for i in range(10):
        t=threading.Thread(target=task,args=(i,))
        t.start()

    现在我们来考虑几个问题,

    如何获取一个线程的唯一标记 ?

    threading.get_ident()  #跟linux进程pid类似

    根据字典自定义一个类似于threading.local功能?

    通过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):    #self.xxx  触发执行
            # print('getattr',item)
            ident=get_ident()
            if ident in self.DIC:
                return self.DIC[ident].get(item)
            return None
    
        def __setattr__(self, key, value):    #self.xxx=123  触发执行
            # print('setattr',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.duo=i
        time.sleep(1)
        print(obj.duo,i)
    
    for i in range(10):
        t=threading.Thread(target=task,args=(i,))
        t.start()

    后续还是有看源码的博客:

    五、简述上下文管理

    1、当请求到来时,在源码中wsgi_app 中 ctx 对象是RequestContext封装所有的对象和请求相关的原始数据,

    这个对象就有request和session,在接下来的对session进行补充,将包含了request/session的ctx对象放到’神奇的地方‘

    这个神奇的地方就是一个大字典,用线程或协程的唯一标识为key,

    2、当视图函数使用的时候:

    假使取一个request.method  ,我们先导入 from  flask import request ,根据当前线程取ctx对象,再取request,再取.method

    3、当请求结束:

    根据当前线程的唯一标记,将’神奇地方‘上的数据移除

  • 相关阅读:
    堆排序优化与几个排序算法时间复杂度
    冒泡排序的实现和优化及其与插入,选择排序的比较
    插入排序的实现与优化并和选择排序进行性能比较
    选择排序的实现以及性能测试
    MD5加密
    低功耗蓝牙BLE [学习笔记]
    反编译[学习笔记]
    Android 混淆[学习笔记]
    北大SQL数据库视频课程笔记
    repo/git Android/CyanogenMod srouce code
  • 原文地址:https://www.cnblogs.com/ManyQian/p/9513909.html
Copyright © 2020-2023  润新知