python-flask框架

面试的时候聊:
        1. Flask中令你影响深刻的是什么?
            - 路由系统
                - 装饰器,带参数的装饰器
                - 额外装饰器
            - 特殊的装饰器
        2.    有没有遇到印象深刻:
            - 本地线程 
            - 最大共享数(文档中写的是最大共享数,但是看源码实现时发现pymysql.threadsafety=1有关),无用。

1. flask知识点:    - flask依赖wsgi,实现wsgi协议的模块:wsgiref(django),werkzeug,uwsgi

        - 创建Flask对象
            app = Flask(__name__)
          def __init__(self, import_name, static_url_path=None,
                             static_folder='static', template_folder='templates',
                             instance_path=None, instance_relative_config=False,
                             root_path=None):
           - 当前模块名          
- 静态文件文件前缀 - 静态文件文件夹位置 - 模板路径 - 配置文件寻找位置: from flask import Flask app = Flask(__name__,instance_path=None, instance_relative_config=True) #只有当 引用文件的方式是 配置文件时,instance这两个参数才有用 #instance_path是指定 从哪个位置开始找settings文件
               #__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。
               app.config.from_pyfile('settings.py') # C:\Users\Administrator\PycharmProjects\s6day120\1.实例化补充 if __name__ == '__main__': app.run() - 配置文件 - 推荐使用对象方式 方式一: app.config['SESSION_COOKIE_NAME'] = 'session_lvning' # 方式二: app.config.from_pyfile('settings.py') settings.py : XXX=123 方式三: import os os.environ['FLAKS-SETTINGS'] = 'settings.py' app.config.from_envvar('FLAKS-SETTINGS') 方式四: app.config.from_object('settings.DevConfig') settings.py : class BaseConfig(object): NNN = 123 class TestConfig(BaseConfig): DB = '127.0.0.1' class DevConfig(BaseConfig): DB = '192.168.1.1' class ProConfig(BaseConfig): DB = '47.18.1.1' - 路由系统 - 通过带参数的装饰器实现的路由关系 注意:其他的装饰器要写在路由装饰器下面 - 两种形式: 第一种: @app.route('/xxxx') def index(): return "Index" 第二种: def index(): return "Index" app.add_url_rule('/xxx', "n1", index) #n1 是别名 - 将函数和url封装到一个 Rule对象 - 将Role对象添加到 app.url_map(Map对象) - 参数: (url路径,endpoint,视图函数名,method=[],default,redirect_to,strict_slashes,subdomain) endpoint 是路由的别名,不写时默认是被装饰的函数名; 反向生成用url_for 来实现 url_for("aaa",**dic)或者 url_for("aaa",x=1) method 允许的请求方式 /index/<int:nid> 不写类型的时候默认是 字符串 def index(nid): print(nid) defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 strict_slashes=None, 对URL最后的 / 符号是否严格要求, redirect_to 直接重定向,跳转的url需要参数时,也得传参,注意:不用加类型 redirect_to("/index/<nid>") subdomain=None 二级域名 :详见day118-06 首先你要有一个主域名 动态的二级域名 - 在本地hosts文件中找IP C:\Windows\System32\drivers\etc ios/lenux系统是在/etc/hosts from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.config['SERVER_NAME'] = 'bjg.com:5000' @app.route("/index",subdomain='<xxxxx>') def index(xxxxx): return "%s.bjg.com" %(xxxxx,) if __name__ == '__main__': app.run() - 扩展Flask的路由系统,让他支持正则 from flask import Flask,url_for app = 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 # 添加到converts中 app.url_map.converters['xxx'] = RegexConverter # 进行使用 @app.route('/index/<xxx("\d+"):nid>',endpoint='xx') def index(nid): url_for('xx',nid=123) return "Index" if __name__ == '__main__': app.run() - 视图函数 请求: request.files 文件信息 request.values 所有的信息 request.form post请求 request.args get请求 响应: reutrn render_template() reutrn redirect() return "" return jsonify(name='alex',age='18') 返回json格式数据 make_response 每一个return的时候flask都做处理 → make_response(返回值), 可以设置cookie 及session 或者更多的其他内容 eg: response = make_response('xxxxx') response.headers['xxx'] = '123123' return response - CBV、FBV 回顾django的cbv: url(r'^login_cbv/',views.Login.as_view) from django.views import View class Login(View): def get(self,request): return render(request,"login.html") def post(self,request): return HttpResponse("post...") 如果是get请求就走 get方法,如果是post请求就走post方法。 flask的cbv def auth(func): def inner(*args, **kwargs): result = func(*args, **kwargs) return result return inner class IndexView(views.MethodView): methods = ['POST'] #只写POST时,只有请求时post时才生效,也就是get函数不执行 decorators = [auth,] 为每一个函数都加上auth装饰器 def get(self): v = url_for('index') print(v) return "GET" def post(self): return "GET" app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) if __name__ == '__main__': app.run() 零碎知识点: root_path 根路径 to_dict() 把url变成字典 urllib.parse 引入 urlencode 把字典变成url形式 quote 和 unquote 把汉字变成乱码/把乱码变成汉字 self.__class__ 找到对象的类 - 模板 1.方法不会自动执行,要加括号,字典也可以用get方法 2.Makeup相当于django的 mark_safe , 或者在前端页面上 |safe Markup("<input type='text' />") 引出 xss 攻击 3.自定义的 标签和 过滤器 @ ,在页面上写的区别, 3.1 需要把test传给前端 def test(a1,a2): return a1+a2 return render_template('index.html',test=test) 使用:{{test(1,19)}} 3.2 所有的模板都可以用 @app.template_global() #加上这个装饰器以后就不需要传了,所有的页面直接就可以使用 def sb(a1, a2): return a1 + a2 + 100 使用:{{sb(1,2)}} 3.3 所有的模板都可以用 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 使用:{{ 1|db(2,3)}} 4.模板的继承和django一样的,include也是一样的 5.hong: {% macro xxxx(name, type='text', value='') %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %} {{ xxxx('n1') }} - 蓝图 - 项目目录规则化 (把一个py文件分成多个py文件 ) 蓝图:小中型项目:结构 大中型项目:结构 - 特殊装饰器 app.before_first_request app.before_request app.after_request 必须要有返回值,并且得有一个形参 - session 设置值 session['xx']=1 取值 session.get('xx') 超时时间的设置 session超时时间如何设置? PERMANENT_SESSION_LIFETIME app.config['SESSION_COOKIE_NAME'] = 'session_lvning' """ '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, #是否实时更新 'PERMANENT_SESSION_LIFETIME': timedelta(days=31) """ session本质是操作的一个字典,在修改session的时候是在内存中操作的,等在return之前 把内存的session字典再返回给你open_session / save_session - flash 同session的原理,区别在于flash取一次就没了 设置值,flash('xxxx') 取值,get_flashed_messages()

2.上下文管理

     什么是上写文?

  上下文个人理解是:程序运行时相关的周围环境,flask里的上下文是指:在请求刚进来的时候把某个数据或者变量放到一个栈里,等你后面什么时候用就去栈里取就行了。在java 和php中上下文被叫做 HttpRequestContext

        a. 创建Local类:
            {
                线程或协程唯一标识: { 'stack':[request],'xxx':[session,] },
                线程或协程唯一标识: { 'stack':[] },
                线程或协程唯一标识: { 'stack':[] },
                线程或协程唯一标识: { 'stack':[] },
            }
        b. 本质
            当请求进来之后,将请求相关数据添加到 [request,]
            以后使用时:去读取
            请求完成之后,将request从列表中移除。
            
        c. 关系
            local= 宋康 = {
                线程或协程唯一标识: { 'stack':[] },
                线程或协程唯一标识: { 'stack':[] },
                线程或协程唯一标识: { 'stack':[] },
                线程或协程唯一标识: { 'stack':[] },
            }
            
            stack=强哥={
                push
                top
                pop
            }
            
            存取数据时,要基于stack来做。
            
        d. Flask和Django区别?
            - 请求相关数据传递方式
                - Django: 参数 
                - Flask: 基于 Local,LocalStack对象
                - 问题:多个请求到来会不会混淆
                    - 单线程
                    - 多线程
                    - 协程
                    解决: from greenlet import getcurrent as get_ident

 3. 数据库连接池

        3.1本地线程    -每一个线程来的时候,都分配一个标示,也就是说每个线程都有自己的数据信息,当取值的时候,只取自己线程的数据,这样实现了线程之间的数据隔离
  
                        import threading
                        import time
                        # 本地线程对象
                        local_values = threading.local()

                        def func(num):

                            """
                            # 第一个线程进来,本地线程对象会为他创建一个唯一标识
                            # 第二个线程进来,本地线程对象会为他创建一个唯一标识
                            {
                                线程1的唯一标识:{name:1},
                                线程2的唯一标识:{name:2},
                            }

                            """
                            local_values.name = num 
                            # 线程停下来了
                            time.sleep(2)
                            # local_values.name,去local_values中根据自己的唯一标识作为key,获取value中name对应的值
                            print(local_values.name, threading.current_thread().name)


                        for i in range(5):
                            th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
                            th.start()
            
        3.2原来连接数据库的方式:   1  #缺点:每次请求反复创建数据库连接,连接数太多
                                         conn = pymysql.connect()
                                         cursor = conn.cursor()
                                         cursor.execute('select * from tb where id > %s',[5,])
                                         result = cursor.fetchall()
                                         cursor.close()
                                         conn.close()
                                         print(result)

                                    2     # 公用一个连接,多线程有问题,加锁→缺点,不能支持并发
                                         with LOCK:
                                             cursor = CONN.cursor()
                                             cursor.execute('select * from tb where id > %s', [5, ])
                                             result = cursor.fetchall()
                                             cursor.close()
                                        
                                             print(result)
                                            
        3.3数据库连接池:
                原理:设置连接池中最大连接数、默认启动时连接池中创建的连接数


              3.3.1.为每个线程创建一个连接,该线程关闭时,不是真正关闭;本线程再次调用时,还是使用的最开始创建的连接。直到线程终止,数据库连接才关闭。(本质是用本地线程实现的)
                ;当很多线程进来时还是会创建很多的连接,所以这种方法也不好。
                    from DBUtils.PersistentDB import PersistentDB
                    import pymysql
                    import threading

                    POOL = PersistentDB(
                        creator=pymysql,  # 使用链接数据库的模块
                        maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
                        setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
                        ping=0,
                        # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
                        closeable=False,
                        # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
                        threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
                        host='127.0.0.1',
                        port=3306,
                        user='root',
                        password='123',
                        database='pooldb',
                        charset='utf8'
                    )

                    def func():
                        conn = POOL.connection()
                        cursor = conn.cursor()
                        cursor.execute('select * from tb1')
                        result = cursor.fetchall()
                        cursor.close()
                        conn.close() # 不是真的关闭,而是假的关闭。

                    for i in range(10):
                        t = threading.Thread(target=func)
                        t.start()
              
              
              3.3.2.创建一个连接池(10个连接),为所有线程提供连接,使用时来进行获取,使用完毕后,再次放回到连接池。      
                                    注意: 连接池中的所有连接都可以被重新使用,原因是因为pymsql.threadsafety的 个数是1
                                    
                                    
                    数据库连接池样板:  
                            xxx.py---------------    
                                    from flask import Flask
                                    from db import POOL

                                    app = Flask(__name__)

                                    @app.route('/index')
                                    def index():
                                      
                                        conn = POOL.connection()
                                        cursor = conn.cursor()
                                        cursor.execute('select * from tb1')
                                        result = cursor.fetchall()
                                        conn.close()
                                        
                                        return '执行成功'

                                    if __name__ == '__main__':
                                        app.run()
                    
                    
                            db.py---------------
                                    import pymysql
                                    from DBUtils.PooledDB import PooledDB, SharedDBConnection
                                    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=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
                                        ping=0,
                                        # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
                                        #ping : 0 或 4最常用
                                        host='127.0.0.1',
                                        port=3306,
                                        user='root',
                                        password='123',
                                        database='pooldb',
                                        charset='utf8'
                                    )
                                    
                                    
                                    
                                    
                    如果有三个线程来连接池(最大连接数:9个,初始化创建了5个)拿连接,有三种情况:
                        1. 他们三个先后顺序来,  同一个连接就够三个线程用了
                        2. 他们来的顺序不定,    有可能需要两个连接
                        3. 他们同时来的,        需要三个链接

4. 单例模式 :    - 推荐:__new__

        - 文件
        - 基于类方法
                        
            # 单例模式:无法支持多线程情况
            """
            class Singleton(object):

                def __init__(self):
                    import time
                    time.sleep(1)

                @classmethod
                def instance(cls, *args, **kwargs):
                    if not hasattr(Singleton, "_instance"):
                        Singleton._instance = Singleton(*args, **kwargs)
                    return Singleton._instance

            import threading

            def task(arg):
                obj = Singleton.instance()
                print(obj)

            for i in range(10):
                t = threading.Thread(target=task,args=[i,])
                t.start()
            """

            # # 单例模式:支持多线程情况
            """
            import time
            import threading
            class Singleton(object):
                _instance_lock = threading.Lock()

                def __init__(self):
                    time.sleep(1)

                @classmethod
                def instance(cls, *args, **kwargs):
                    if not hasattr(Singleton, "_instance"):
                        with Singleton._instance_lock:
                            if not hasattr(Singleton, "_instance"):
                                Singleton._instance = Singleton(*args, **kwargs)
                    return Singleton._instance


            def task(arg):
                obj = Singleton.instance()
                print(obj)
            for i in range(10):
                t = threading.Thread(target=task,args=[i,])
                t.start()
            time.sleep(20)
            obj = Singleton.instance()
            print(obj)
            """

        - 基于__new__方法
        
                引出:new,call,init 方法及区别
                    """
                1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法
                2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)

                # 第0步: 执行type的 __init__ 方法【类是type的对象】
                class Foo:
                    def __init__(self):
                        pass

                    def __call__(self, *args, **kwargs):
                        pass

                # 第1步: 执行type的 __call__ 方法
                #        1.1  调用 Foo类(是type的对象)的 __new__方法,用于创建对象。
                #        1.2  调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
                obj = Foo()
                # 第2步:执行Foodef __call__ 方法
                obj()
                """
                
                
                """
                class SingletonType(type):
                    def __init__(self,*args,**kwargs):
                        super(SingletonType,self).__init__(*args,**kwargs)

                    def __call__(cls, *args, **kwargs):
                        obj = cls.__new__(cls,*args, **kwargs)
                        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
                        return obj

                class Foo(metaclass=SingletonType):
                    def __init__(self,name):
                        self.name = name
                    def __new__(cls, *args, **kwargs):
                        return object.__new__(cls, *args, **kwargs)

                obj = Foo('name')
                """
                
                import threading
                class Singleton(object):
                    _instance_lock = threading.Lock()

                    def __init__(self):
                        pass

                    def __new__(cls, *args, **kwargs):
                        if not hasattr(Singleton, "_instance"):
                            with Singleton._instance_lock:
                                if not hasattr(Singleton, "_instance"):
                                    Singleton._instance = object.__new__(cls, *args, **kwargs)
                        return Singleton._instance

                obj1 = Singleton()
                obj2 = Singleton()
                print(obj1,obj2)   #  <__main__.Singleton object at 0x0000029B7FE127F0>    <__main__.Singleton object at 0x0000029B7FE127F0>

        - 基于metaclass方法
            import threading

            class SingletonType(type):
                _instance_lock = threading.Lock()
                def __call__(cls, *args, **kwargs):
                    if not hasattr(cls, "_instance"):
                        with SingletonType._instance_lock:
                            if not hasattr(cls, "_instance"):
                                cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
                    return cls._instance

            class Foo(metaclass=SingletonType):
                def __init__(self,name):
                    self.name = name


            obj1 = Foo('name')
            obj2 = Foo('name')
            print(obj1,obj2)   #  <__main__.Foo object at 0x0000017B6A612898>   <__main__.Foo object at 0x0000017B6A612898>
        
        在哪应用了单例模式:
            a. stark组件
            b. 数据库连接池 

5.Session

        5.1- 读Flask session源码

        5.2- 流程:
            当请求第一次进来,生成随机字符串:sidfnsdfisdfs
                - 发给用户cookie
                - 保存到session字典中
                
                PS: 调用 stack(强哥)将随机字符串和对应的值放到 local(宋康)
                
            视图函数使用
                session = LocalProxy(partial(_lookup_req_object, 'session'))
                
            请求处理完毕
                将session做持久化:
                    - 存到数据
                    - 存到redis
                    - 存到加密cookie中
        
        5.3- 自定义session:
            from flask import Flask,request,session
            app = Flask(__name__)
            app.secret_key = 'sdfsdfsd'
            from flask.sessions import SessionInterface,SessionMixin
            import uuid
            import json
            from flask.sessions import SessionInterface
            from flask.sessions import SessionMixin
            from itsdangerous import Signer, BadSignature, want_bytes

            class MySession(dict, SessionMixin):
                def __init__(self, initial=None, sid=None):
                    self.sid = sid
                    self.initial = initial
                    super(MySession, self).__init__(initial or ())

                def __setitem__(self, key, value):
                    super(MySession, self).__setitem__(key, value)

                def __getitem__(self, item):
                    return super(MySession, self).__getitem__(item)

                def __delitem__(self, key):
                    super(MySession, self).__delitem__(key)


            class MySessionInterface(SessionInterface):
                session_class = MySession
                container = {
                    # 'asdfasdfasdfas':{'k1':'v1','k2':'v2'}
                    # 'asdfasdfasdfas':"{'k1':'v1','k2':'v2'}"
                }

                def __init__(self):
                    pass
                    # import redis
                    # self.redis = redis.Redis()

                def _generate_sid(self):
                    return str(uuid.uuid4())

                def _get_signer(self, app):
                    if not app.secret_key:
                        return None
                    return Signer(app.secret_key, salt='flask-session',
                                  key_derivation='hmac')

                def open_session(self, app, request):
                    """
                    程序刚启动时执行,需要返回一个session对象
                    """
                    sid = request.cookies.get(app.session_cookie_name)
                    if not sid:
                        # 生成随机字符串,并将随机字符串添加到 session对象中
                        sid = self._generate_sid()
                        return self.session_class(sid=sid)

                    signer = self._get_signer(app)
                    try:
                        sid_as_bytes = signer.unsign(sid)
                        sid = sid_as_bytes.decode()
                    except BadSignature:
                        sid = self._generate_sid()
                        return self.session_class(sid=sid)

                    # session保存在redis中
                    # val = self.redis.get(sid)
                    # session保存在内存中
                    val = self.container.get(sid)

                    if val is not None:
                        try:
                            data = json.loads(val)
                            return self.session_class(data, sid=sid)
                        except:
                            return self.session_class(sid=sid)
                    return self.session_class(sid=sid)

                def save_session(self, app, session, response):
                    """
                    程序结束前执行,可以保存session中所有的值
                    如:
                        保存到resit
                        写入到用户cookie
                    """
                    domain = self.get_cookie_domain(app)
                    path = self.get_cookie_path(app)
                    httponly = self.get_cookie_httponly(app)
                    secure = self.get_cookie_secure(app)
                    expires = self.get_expiration_time(app, session)

                    val = json.dumps(dict(session))

                    # session保存在redis中
                    # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
                    # session保存在内存中
                    self.container.setdefault(session.sid, val)

                    session_id = self._get_signer(app).sign(want_bytes(session.sid))

                    response.set_cookie(app.session_cookie_name, session_id,
                                        expires=expires, httponly=httponly,
                                        domain=domain, path=path, secure=secure)



            app.session_interface = MySessionInterface()
            # app.session_interface = Foo()
            # app.session_interface
            # app.make_null_session()
            @app.route('/index')
            def index():
                print('网站的所有session',MySessionInterface.container)
                print(session)
                session['k1'] = 'v1'
                session['k2'] = 'v2'
                del session['k1']

                # 在内存中操作字典....
                # session['k1'] = 'v1'
                # session['k2'] = 'v2'
                # del session['k1']

                return "xx"

            if __name__ == '__main__':
                app.__call__
                app.run()
        
        5.4 最常用
            pip3 install flask-session
            
            #!/usr/bin/env python
            # -*- coding:utf-8 -
            from flask import Flask,current_app,session
            from flask_session import Session
            app = Flask(__name__)
            app.debug = True
            app.secret_key = 'xxxx'

            # 为Flask-session组件提供的配置
            # import redis
            # app.config['SESSION_TYPE'] = 'redis'  # session类型为redis
            # app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port='6379', password='123123')  # 用于连接redis的配置
            # app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀
            # app.config['SESSION_PERMANENT'] = False  # 如果设置为True,则关闭浏览器session就失效。
            # app.config['SESSION_USE_SIGNER'] = False  # 是否对发送到浏览器上 session:cookie值进行加密
            # Session(app)
            #
            # import memcache
            # app.config['SESSION_TYPE'] = 'memcached' # session类型为memcached
            # app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
            # app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密
            # app.config['SESSION_KEY_PREFIX'] = 'session:' # 保存到session中的值的前缀
            # app.config['SESSION_MEMCACHED'] = memcache.Client(['10.211.55.4:12000'])
            # Session(app)

            app.config['SESSION_TYPE'] = 'filesystem'  # session类型为filesystem
            app.config['SESSION_FILE_DIR'] = r'C:\Users\Administrator\PycharmProjects\day121\2.flask-session组件'  # session类型为redis
            app.config['SESSION_FILE_THRESHOLD'] = 500  # 存储session的个数如果大于这个值时,就要开始进行删除了
            app.config['SESSION_FILE_MODE'] = 384  # 文件权限类型

            app.config['SESSION_PERMANENT'] = True  # 如果设置为True,则关闭浏览器session就失效。
            app.config['SESSION_USE_SIGNER'] = False  # 是否对发送到浏览器上session的cookie值进行加密
            app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀

            Session(app)


            @app.route('/index')
            def index():
                session['k1'] = 'v1'
                return 'xx'

            if __name__ == '__main__':
                app.run()

6.blinker  信号

        pip3 install blinker
        
        6.1 内置信号
            10个信号:
                2. request_started = _signals.signal('request-started')                # 请求到来前执行
                5. request_finished = _signals.signal('request-finished')              # 请求结束后执行
                 
                3. before_render_template = _signals.signal('before-render-template')  # 模板渲染前执行
                4. template_rendered = _signals.signal('template-rendered')            # 模板渲染后执行
                 
                2/3/4/5或不执行 got_request_exception = _signals.signal('got-request-exception')    # 请求执行出现异常时执行
                 
                6. request_tearing_down = _signals.signal('request-tearing-down')      # 请求执行完毕后自动执行(无论成功与否)
                7. appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 请求上下文执行完毕后自动执行(无论成功与否)
                 
                 
                1. appcontext_pushed = _signals.signal('appcontext-pushed')            # 请求app上下文push时执行
                
                8. appcontext_popped = _signals.signal('appcontext-popped')            # 请求上下文pop时执行
                
                message_flashed = _signals.signal('message-flashed')                   # 调用flask在其中添加数据时,自动触发
            
            
            问题:
                特殊的装饰器和信号有什么区别?
                    - 装饰器返回值有意义
                    - 信号用于做什么呢?
                        - 降低代码之间的耦合
                        
        6.2 自定义信号 :创建信号→注册→触发
                from flask import Flask,flash
                from flask.signals import _signals
                app = Flask(__name__)

                wh = _signals.signal('wh')


                # 定义函数
                def luominwen(*args,**kwargs):
                    print('罗姑娘',args,kwargs)

                # 定义函数
                def shaowei(*args,**kwargs):
                    print('少姑娘',args,kwargs)

                # 将函数注册到request_started信号中: 添加到这个列表
                wh.connect(luominwen)
                wh.connect(shaowei)


                @app.route('/index')
                def index():
                    # 触发这个信号:执行注册到列表中的所有函数
                    # 发送短信,邮件,微信
                    wh.send(sender='xxx',a1=123,a2=456)
                    return "xx"

                if __name__ == '__main__':
                    app.__call__
                    app.run()

    
     6.3Django内置
                    Request/response signals
                        request_started             # 请求到来前,自动触发
                        request_finished            # 请求结束后,自动触发
                        got_request_exception       # 请求异常后,自动触发
                    
                    Model signals
                        pre_init                    # django的modal执行其构造方法前,自动触发
                        post_init                   # django的modal执行其构造方法后,自动触发
                        
                        pre_save                    # django的modal对象保存前,自动触发
                        post_save                   # django的modal对象保存后,自动触发, 它可以判断是增加的还是修改的
                        
                        pre_delete                  # django的modal对象删除前,自动触发
                        post_delete                 # django的modal对象删除后,自动触发
                        
                        m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
                        
                        class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
                        
                    Management signals
                        pre_migrate                 # 执行migrate命令前,自动触发
                        post_migrate                # 执行migrate命令后,自动触发
                    
                    Test signals
                        setting_changed             # 使用test测试修改配置文件时,自动触发
                        template_rendered           # 使用test测试渲染模板时,自动触发
                    Database Wrappers
                        connection_created          # 创建数据库连接时,自动触发
                
                需求:新浪面试题,数据库12张表,每张表创建一条数据时,记录一条日志。
             答案: 可以重写 django里面orm操作的save 方法,或者 使用信号

7. wtforms

        - wtforms的源码
        - 使用
    metaclass的另外一种方式:
        class MyType(type):
            def __init__(self,*args,**kwargs):
                print('xxxx')
                super(MyType,self).__init__(*args,**kwargs)

            def __call__(cls, *args, **kwargs):
                obj = cls.__new__(cls,*args, **kwargs)
                cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
                return obj

        def with_metaclass(base):
            return MyType("MyType",(base,),{})

        class Foo(with_metaclass(object)):
            def __init__(self,name):
                self.name = name

        #打印结果:  xxxx    xxxx

8. flask的简单 使用:

        - 蓝图
        - 配置 from_objects
        - flask-session
        - 记录:请求到来写日志
        - wtforms
        - DBUtils
        - 单例模式
        PS: 连接数据库,对用户表进行:登录和注册

 9. 导出程序内应用的所有模块

# 获取环境中所有安装的模块
        pip3 freeze          #在终端查看
        pip3 freeze > requirements.txt    #写入requirements.txt文件中
        
# pip3 install pipreqs
# 获取当前所在程序目录中涉及到的所有模块,并自动生成 requirements.txt 且写入内容。
pipreqs ./
        
        
以后别人给你程序:
     requirements.txt
            
进入程序目录:
     pip3 install -r requirements.txt

 

posted @ 2018-01-10 16:42  Cool·  阅读(1576)  评论(0编辑  收藏  举报