• python Flask web框架


    目录:

    --> Flask
      --> 配置文件
        --> 配置文件解析
        --> 配置文件导入

      --> 路由
        --> 路由参数
        --> 常用路由匹配

      --> 请求相关 & 响应
        --> request 参数
        --> response 参数
        --> 打包模板和参数

      --> 模板 jinja2
        --> 模板导入/继承
        --> 前段/后端 安全渲染
        --> 前段自定义函数 macro
        --> 后端自定义前段函数
          --> @app.template_global()
          --> @app.template_filter()

      --> 请求扩展
        --> @app.before_first_request
        --> @app.before_request
        --> @app.after_request

      --> 错误页面自定制

      --> 闪现
      --> 蓝图
      --> 中间件
      --> 信号
      --> 上下文管理
        --> threading.local
        --> 请求上下文(requestContext)
          --> request
          --> session
        --> 应用上下文:AppContext
          --> app(current_app)
          --> g
        --> 实现细节
          --> 利用threading.local 的线程 唯一ID标识符
          --> requestcontext对象通过localstack添加到Local 栈中
          --> 导入request(session、current_app、g)是localproxy -> 偏函数 ->Localstack -> Local
          --> requestcontext的auto_pop -> localstaack.pop ->local中移除
        --> 多app应用
        --> 技术点:LocalProxy、chain,偏函数
        --> 中间件/信号 执行顺序

    falsk 配置文件解析

    class BaseConfig(object):
        
    DEBUG = True
        # TESTING = False
        # PROPAGATE_EXCEPTIONS = None
        # PRESERVE_CONTEXT_ON_EXCEPTION = None
        SECRET_KEY = str(uuid.uuid4())
        # PERMANENT_SESSION_LIFETIME = None
        # USE_X_SENDFILE = False
        # LOGGER_NAME = None
        # LOGGER_HANDLER_POLICY = None
        # SERVER_NAME = None
        # APPLICATION_ROOT = None
        # SESSION_COOKIE_NAME = None
        # SESSION_COOKIE_DOMAIN = None
        # SESSION_COOKIE_PATH = None
        # SESSION_COOKIE_HTTPONLY = True
        # SESSION_COOKIE_SECURE = False
        # SESSION_REFRESH_EACH_REQUEST = True
        # MAX_CONTENT_LENGTH = None
        # SEND_FILE_MAX_AGE_DEFAULT = None
        # TRAP_BAD_REQUEST_ERRORS = False
        # TRAP_HTTP_EXCEPTIONS = False
        # EXPLAIN_TEMPLATE_LOADING = False
        # PREFERRED_URL_SCHEME = None
        # JSON_AS_ASCII = True
        # JSON_SORT_KEYS = True
        # JSONIFY_PRETTYPRINT_REGULAR = True
        # JSONIFY_MIMETYPE = None
        # TEMPLATES_AUTO_RELOAD = None
    
        # 数据库配置
        SQLALCHEMY_DATABASE_URL ="mysql://root:123456@1.1.1.1:3306/anec"
        SQLALCHEMY_TRACK_MODIFICATIONS = True
    
    class TestingConfig(BaseConfig):
        pass
    
    
    class DevelopmentConfig(BaseConfig):
        pass
    
    class ProductionConfig(BaseConfig):
        pass

    falsk 配置文件导入:

    # flask 配置文件介绍:
    # 方式一:
    # Session, Cookies以及一些第三方扩展都会用到SECRET_KEY值
    # app.config['SECRET_KEY'] = '123456'
    # app.config['DEBUG'] = True
    
    # 方式二:(只有部分可以如此操作)
    # app.secret_key = '123456'
    
    # 方式三:(导入配置文件的方式)
    # app.config.from_pyfile('setting.py')
    
    # 方式四:(推荐方式:在配置文件中写一个类,将配置写在类里面,再导入)
    app.config.from_object('setting.Text')

    方式四 setting文件

    # 共有的
    class Config(object):
        SECRET_KEY = '123456'
        DEBUG = False
    
    class Text(Config):
        DEBUG = True
        SECRET_KEY = 'abcd'

    路由参数

    # 路由系统:
    # 基于装饰器来实现,但是究其本质是通过下面函数实现的
    # app.add_url_rule(rule='/路径',endpoint='别名',view_func='视图函数',methods='访问的类型/["GET","POST"]')
    
    # CBV 的flask 方式:
    # from flask import views
    # 配置视图
    # class Text(views.MethodView):
    #     methods = ['GET','POST']
    #     # 登录装饰器
    #     # decorators = [login_required,]
    #
    #     def get(self):
    #         return 'Text_Class_get'
    #
    #     def post(self):
    #         return 'Text_Class,post'
    #
    # 配置路由
    # app.add_url_rule(rule='/text/',view_func=Text.as_view(name='text'))
    
    # app.add_url_rule 和 app.route
    # 参数:
    # rule: url 规则
    # view_func 视图函数名称
    # defaults=None 默认值,当url中没有参数
    # endpoint=None 反向生成url,不能重名,在使用装饰器时,没有导入@wraps(func)则需要区分
    # methods=None 允许的请求方式,如:['GET','POST']
    # strict_slashes=None 对URL最后的 / 符号是否严格要求
    # redirect_to=None 重定向地址
    # subdomain=None 子域名访问,需要配合域名使用
    View Code

    常用路由匹配方式

    # 常用路由方式:
    # @app.route('/user/<username>')
    # @app.route('/user/<int:post_id>')
    # @app.route('/user/<float:post_id>')
    # @app.route('/user/<path:PATH>')
    # @app.route('/user/',methods=['GET','POST'])
    View Code

    请求相关 & 响应

    request

    # request
    # request.method
    # request.args
    # request.form
    # request.values
    # request.cookies
    # request.headers
    # request.path
    # request.full_path
    # request.script_root
    # request.url
    # request.base_url
    # request.url_root
    # request.host_url
    # request.host
    
    # request.files
    # obj = request=files['the_file_name']
    # obj.save('/var/www/uploads'+secure_filename(f.filename))
    View Code

    response

    # response
    # return "字符串"
    # render_templates('html模板',返回参数)
    # return redirect('/index.html')
    
    # 打包模板和参数
    # response = make_response(render_template("index.html"))
    # response 是flask.wrappers.Response类型
    # response.delete_cookie("key")
    # response.set_cookie("key",'value')
    # response.headers['X-something'] = 'A value'
    # return response
    View Code

    模板 jinja2

    # 模板:(模板也支持导入,继承)
    # 跟 django 都是使用的jinja2 模板
    # 前段 安全渲染 {func | safe }
    # 后端 安全渲染  import Markup 函数
    
    # # 新增功能
    # {% macro 自定义函数名(参数,参数N) %}
    #     <span>{{参数}}---{{参数n}}</span>
    #     <span>{{参数}}---{{参数n}}</span>
    #     <span>{{参数}}---{{参数n}}</span>
    # {% endmacro%}
    #
    # # 调用上面的函数
    # {{自定义函数(参数)}}
    
    # ------------
    
    # 模板内自定义函数(类似django simple_tag)
    # @app.template_global()
    # def sb(a1,a2):
    #     return a1 + a2
    
    # 模板中使用方法:
    # {{sb(1,2)}}
    
    
    # ------------
    # 后端自定义前段函数
    # @app.template_filter()
    # def sb2(a1,a2,a3):
    #     return a1 + a2 + a3
    
    # 模板中使用方法:
    # {{1|sb2(2,3)}}
    
    # url_for('参数')  参数指向的书 views 视图中的函数名,而不是路由名

    请求扩展

    # 请求扩展 (django中的中间件)
    
    # 第一次访问执行:
    # @app.before_first_request
    # def first(*args,**kwargs)
    #     pass
    
    # # 先进后出
    # @app.before_request
    # def preocess_request(*args,**kwargs):
    #     # 这里可以做登录认证
    #     print('request_1')
    #
    # @app.before_request
    # def preocess_request2(*args,**kwargs):
    #     # 这里可以做登录认证
    #     print('request_2')
    #
    # @app.after_request
    # def preocess_response(response):
    #     print('response_1')
    #     return response
    #
    # @app.after_request
    # def preocess_response2(response):
    #     print('response_2')
    #     return response
    View Code

    错误页面自定制

    # # 错误页面 自定制
    #
    # @app.errorhandler(404)
    # def error_404(arg):
    #     return "页面不存在!"

    闪现

    # # 闪现 : 临时数据操作 如:显示错误信息
    # from flask import flash,get_flashed_messages
    #
    # @app.route('/get')
    # def get():
    #     data = get_flashed_messages()
    #     # data = get_flashed_messages(category_filter=['l1']) 分类取数据
    #     print(data)
    #     return "get"
    #
    # @app.route('/set')
    # def set():
    #     flash('aaaaaa')
    #     # flash('aaaaaa',category='l1') #可以数据分类
    #     return "set"

    上下文管理

    # 上下文管理:
    # 1.知道flask 依赖的组件: WSGI、jinja2、Werkzeug,flask 框架是组装件的粘合剂
    # client --- wsgi -----flask --- jinja2 ----werkzeug
    # 2.flask 用threading.local 做了一个Local对象 存放请求信息
    
    # 引入步骤:
    # Flask()实例化 -> 将请求数据传入Flask实例 -> 将数据push 至 _request_ctx_stack,_request_ctx_stack实质是 LocalStack()
    # LocalStack() 初始化时 又实例化了 Local() ,local初始化 最终以类似列表的方式 保存object.__setattr__(self, '__storage__', {})
    
    # 请求到来:
    #   --ctx = 封装requestContext(request,ssision)
    #   --ctx放进Local中
    # 执行视图时
    #   --导入request
    #   --request   ---> LocalProxy对象中 __getattr__获取对应的请求
    #       ---调用 _lookup_req_object函数:去local 中酱requestcontext 将获取到,再去requestcontext中获取request或session
    # 请求结束
    #   --ctx.auto_pop()
    #   --ctx从local中移除
    
    # --> 上下文管理
    #       --> threading.local
    # --> 请求上下文(requestContext)
    #       --> request
    #       --> session
    # --> 应用上下文: AppContext
    #       --> app(current_app)
    #       --> g
    # --> 实现细节
    #       --> 利用threading.local的线程唯一ID标识符
    #       --> requestcontext对象通过localstack添加到Local栈中
    #       --> 导入request(session、current_app、g)是localproxy -> 偏函数 ->Localstack -> Local
    #       --> requestcontext的auto_pop -> localstaack.pop ->local中移除
    View Code

    信号

    # # 示例一:(自定义信号)
    # from flask.signals import _signals
    #
    # xinhao = _signals.signal('before-render-template')#创建信号
    #
    # #定义函数
    # def wahaha(*args,**kwargs):
    #     print("111",args,kwargs)
    #
    # # 将函数注册到信号中,添加到这个列表
    # xinhao.connect(wahaha)
    #
    # @app.route("/zzz")
    # def zzz():
    #     # 信号是通过send 方法 出发的!!!!!!!!!
    #     xinhao.send(sender='xxx',a1=123,a2=456)  #触发这个信号,执行注册到这个信号列表中的所有函数,此处的参数个数需要与定义的函数中的参数一致
    #     print("ok")
    #     return "OK"
    
    # ---------------------------------------------------------------
    
    # # 示例二:(内置信号使用)
    # from flask.signals import _signals
    #
    # bf = _signals.signal('before-render-template')
    # bf2 = _signals.signal('template-rendered')
    #
    # def text(*args,**kwargs):
    #     print("111")
    #
    # bf.connect(text)
    # bf2.connect(text)
    View Code

    信号与中间件的执行顺序

    # 信号 依赖于 blinker 模块 (信号只执行记录,并不能中断流程,而中间件可以中断)
    # pip install blinker
    
    # 内置信号 以及执行顺序:
    # --> a 中间件:before_first_request
    # --->1 appcontext_pushed = _signals.signal('appcontext-pushed')  # 请求app上下文push时执行
    # --->2 request_started = _signals.signal('request-started')  # 请求到来前执行
    
    # --> b 中间件:before_request
    # --->3 before_render_template = _signals.signal('before-render-template')  # 模板渲染前执行
    # --->4.template_rendered = _signals.signal('template-rendered')  # 模板渲染后执行
    
    # --> c 中间件:after_request
    # -->   session.save_session()
    # --->5 request_finished = _signals.signal('request-finished')  # 请求结束后执行
    # --->6.request_tearing_down = _signals.signal('request-tearing-down')  # 请求执行完毕后自动执行(无论成功与否)
    
    # --->7.appcontext_tearing_down = _signals.signal('appcontext-tearing-down')  # 请求上下文执行完毕后自动执行(无论成功与否)
    # --->8.appcontext_popped = _signals.signal('appcontext-popped')  # 请求上下文pop时执行
    
    # 发生在2 / 3 / 4 / 5或不执行
    # got_request_exception = _signals.signal('got-request-exception')  # 请求执行出现异常时执行
    
    # message_flashed = _signals.signal('message-flashed')  # 调用flask在其中添加数据时,自动触发
    View Code

    多APP 应用

    # 多APP 应用
    # web 访问多app应用时,上下文管理是如何实现的?
    
    # from werkzeug.wsgi import DispatcherMiddleware
    # from werkzeug.serving import run_simple
    #
    # app01 = Flask('app01')
    # app02 = Flask('app02')
    #
    # @app01.route('/index')
    # def app01_index():
    #     return "app01"
    #
    # @app02.route('/index')
    # def app02_index():
    #     return "app02"
    #
    # app = DispatcherMiddleware(app01,{
    #     '/app02前缀':app02,
    # })
    #
    # if __name__=="__main__":
    #     run_simple('localhost',8002,app)
    View Code

    session 相关

    #&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    # 使用session 前 必须配置SECRET_KEY!!!
    # session 操作:(session就相当于是一个字典!)
    # session['类型'] = 值
    # session.pop['类型']
    # del session['类型']
    #&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

     session 第三方组件(自定制session保存位置)

    # flask session 机制
    '''
    ->请求刚进来:获取随机字符串,存在,则去容器 中获取原来的个人数据,否则创建一个空的容器
        ->对象(随机字符串,{请求数据})
    ->视图:读取内存中对象
    ->响应:内存对象 将对象数据保存到数据库(没有指定数据库的话 保存在内存中),把随机字符串写到用户cookie中
    '''
    # 使用 方式一
    # flask-session 组件
    # from flask_session import Session
    # import pymongo
    #
    # app.config['SESSION_TYPE'] = 'mongodb'  # session类型为redis
    #
    # app.config['SESSION_MONGODB'] = pymongo.MongoClient('localhost',27017)
    # app.config['SESSION_MONGODB_DB'] = 'text'
    # app.config['SESSION_MONGODB_COLLECT'] = 'col'
    #
    # app.config['SESSION_PERMANENT'] = True  # 如果设置为True,则关闭浏览器session就失效。
    # app.config['SESSION_USE_SIGNER'] = False  # 是否对发送到浏览器上session的cookie值进行加密
    # app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀
    #
    # Session(app)
    
    
    # 使用 方式二
    
    # from flask_session import MongoDBSessionInterface
    # app.session_interface = MongoDBSessionInterface("参数!")
    View Code

    一些问答

    # &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    # 问题1 多线程时如何体现的?
    # 问题2 flask的local 中保存数据时,使用列表创建出来的栈,为什么用栈?
    #       --如果写web程序,web运行环境,栈中永远保存1条数据(可以不用栈)
    #       --写脚本获取app信息,可能存在app上下文嵌套关系
    
    '''
    from  flask import Flask,current_app,globals,_app_ctx_stack
    
    app1=Flask('app01')
    app1.debug = False
    
    app2=Flask('app02')
    app2.debug = False
    
    with app1.app_context():
        print(_app_ctx_stack._local.__storage__)
        print(current_app.config['DEBUG'])
    
        with app2.app_context():
        print(_app_ctx_stack._local.__storage__)
        print(current_app.config['DEBUG'])
    
    '''
    # &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

    flask 实现装饰器方式:引入(wraps)

    from functools import wraps
    # flask 实现登录装饰器的功能
    def login_required(func):
        @wraps(func)
        # @wraps(view_func)的作用:     不改变使用装饰器原有函数的结构(如__name__, __doc__)
        # 不使用wraps可能出现的ERROR:   view_func...endpoint...map...
        def wrapper(*args,**kwargs):
            if session.get('user'):
                return func(*args,**kwargs)
            else:
                return redirect('/')
        return wrapper
    
    # 装饰器实现的方式:
    @app.route('/index/',methods=['GET'])
    @login_required                                         # flask 登录装饰器
    def index():
        return render_template('index.html',u_list=data)
    
    @app.route("/detail/<int:id>",methods=['GET'])
    def detail(id):
        return str(id)
    View Code
  • 相关阅读:
    容器网络(一)docker容器网络驱动
    双指针遍历/滑动窗口 —— 209_长度最小的子数组
    双指针遍历/滑动窗口 —— 121_买卖股票的最佳时机
    双指针遍历/滑动窗口 —— 42_接雨水
    双指针遍历/滑动窗口 —— 26_删除排序数组中的重复项
    双指针遍历/滑动窗口 —— 16_最接近的三数之和
    双指针遍历/滑动窗口 —— 15_三数之和
    双指针遍历/滑动窗口 —— 11_盛最多水的容器
    双指针遍历/滑动窗口 —— 3_无重复字符的最长子串
    链表操作 —— 206_反转链表
  • 原文地址:https://www.cnblogs.com/Anec/p/10469892.html
Copyright © 2020-2023  润新知