• Python Flask框架 入门详解与进阶


    1.Flask框架 入门

    flask是一个非常轻量化的后端框架,与django相比,它拥有更加简洁的框架。django功能全而强大,它内置了很多库包括路由,表单,模板,基本数据库管理等。flask框架只包含了两个核心库(Jinja2 模板引擎和 Werkzeug WSGI 工具集),需要什么库只需要外部引入即可,让开发者更随心所欲的开发应用
    Flask文档
    中文文档(http://docs.jinkan.org/docs/flask
    英文文档(http://flask.pocoo.org/docs/1.0/

    2.环境搭建

    2.1.安装flask

    1.创建虚拟环境

    mkvirtualenv flask -p python3
    
    • 1

    2.激活虚拟环境

    workon flask
    
    • 1

    3.安装flask

    pip install flask
    
    • 1

    2.2.flask程序编写

    1.创建test.py文件

    # 导入Flask类
    from flask import Flask
    
    #Flask类接收一个参数__name__
    app = Flask(__name__)
    
    # 装饰器的作用是将路由映射到视图函数index
    @app.route('/')
    def index():
        return 'Hello World'
    
    # Flask应用程序实例的run方法启动WEB服务器
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.启动运行

    python test.py
    
    • 1

    2.3.参数说明

    1.Flask对象的初始化参数

    Flask 程序实例在创建的时候,需要默认传入当前 Flask 程序所指定的包(模块)
    
    Flask 应用程序在创建的时候一些需要我们关注的参数:
    
    import_name
    Flask程序所在的包(模块),传__name__就可以
    其可以决定 Flask 在访问静态文件时查找的路径
    static_url_path
    静态文件访问路径,可以不传,默认为:/ + static_folder
    static_folder
    静态文件存储的文件夹,可以不传,默认为 static
    template_folder
    模板文件存储的文件夹,可以不传,默认为 templates
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    默认参数情况

    app = Flask(__name__)
    
    • 1

    文件目录
    文件目录
    访问http://127.0.0.1:5000/static/fu.png就可以访问到图片
    完整参数情况下

    # 导入Flask类
    from flask import Flask
    
    #Flask类接收一个参数__name__,static_url_path是静态文件访问路径,static_folder静态文件存储的文件夹
    app = Flask(__name__, static_url_path='w',static_folder='static_file')
    
    # 装饰器的作用是将路由映射到视图函数index
    @app.route('/')
    def index():
        return 'Hello World'
        
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    文件目录
    在这里插入图片描述

    此时访问http://127.0.0.1:5000/w/IMG_5311.jpg,才可以访问到图片

    2.应用程序配置参数

    对于Flask对象初始化参数仅仅设置的是Flask本身的属性,比如:
    Flask从哪里读取静态文件,Flask从哪里读取模板文件
    
    还需要应用程序配置参数设置的,是一个Web应用工程的相关信息,比如:
    数据库的连接信息,日志的配置信息,自定义的配置信息
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用方式
    Flask将配置信息保存到了app.config属性中
    读取
    app.config.get(name)
    app.config[name]
    设置

    第一种 :从配置对象中加载 app.config.from_object(DefaultConfig)

    test_config.py

    # 导入Flask类
    from flask import Flask
    
    # 配置对象方式加载配置信息
    class DefaultConfig(object):
        """
        默认配置信息
        """
        SECRET_KEY = 'FDDKKKGFHFHRHNGGGKLTUIRKTKJBNSDFFFWET'
    
    #Flask类接收一个参数__name__
    app = Flask(__name__, static_url_path='/w', static_folder='static_file')
    
    # 设置
    app.config.from_object(DefaultConfig)
    
    #定义视图
    @app.route('/')
    def index():
        # 读取配置信息
        print(app.config['SECRET_KEY'])
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    运行程序在后台就会打印出来 SECRET_KEY

    第二种:从配置文件中加载

    在当前目前创建一个setting.py文件,里面写入配置信息

    SECRET_KEY = '我是配置文件信息'
    
    • 1

    test_config.py

    # 导入Flask类
    from flask import Flask
    
    # 配置对象方式加载配置信息
    class DefaultConfig(object):
        """
        默认配置信息
        """
        SECRET_KEY = 'FDDKKKGFHFHRHNGGGKLTUIRKTKJBNSDFFFWET'
    
    #Flask类接收一个参数__name__
    app = Flask(__name__, static_url_path='/w', static_folder='static_file')
    
    # 设置
    # app.config.from_object(DefaultConfig)
    app.config.from_pyfile('setting.py')
    
    #定义视图
    @app.route('/')
    def index():
        # 读取配置信息
        print(app.config['SECRET_KEY'])
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    运行就会打印出配置文件的信息

    第三种:从环境变量中加载
    在Linux系统中设置和读取环境变量的方式
    export 变量名=变量值  # 设置
    echo $变量名  # 读取
    
    # 例如
    export MYCONFIG=python
    echo $MYCONFIG
    
    在windows系统里是
    set 变量名=变量值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    test_config.py

    # 导入Flask类
    from flask import Flask
    
    # 配置对象方式加载配置信息
    class DefaultConfig(object):
        """
        默认配置信息
        """
        SECRET_KEY = 'FDDKKKGFHFHRHNGGGKLTUIRKTKJBNSDFFFWET'
    
    #Flask类接收一个参数__name__
    app = Flask(__name__, static_url_path='/w', static_folder='static_file')
    
    # 设置
    # app.config.from_object(DefaultConfig)
    # app.config.from_pyfile('setting.py')
    
     # silent=False 表示不安静的处理,没有值时报错通知,默认为False
     # silent=True 表示安静的处理,即使没有值也让Flask正常的运行下去
    app.config.from_envvar('ENV_SETTING', silent=True)
    
    #定义视图
    @app.route('/')
    def index():
        # 读取配置信息
        print(app.config['SECRET_KEY'])
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Flask使用环境变量加载配置就是通过环境变量值找到配置文件,再读取配置文件的信息,其使用方式为
    我用windows来演示

    在这里插入图片描述
    Pycharm设置环境变量
    在这里插入图片描述

    在这里插入图片描述

    项目中的常用方式
    • app.config.from_object(配置对象)
      优点:继承,复用
      缺点:敏感信息暴露
    • app.config.from_pyfile(配置文件)
      优点:独立文件,保护敏感数据
      缺点:不能继承,文件路径固定不灵活
    • app.config.from_envvar(环境变量)
      优点:独立文件,保护敏感数据,文件路径不固定,灵活
      缺点:不方便,记得设置环境变量
    from flask import Flask
    
    def create_flask_app(config):
        """
        创建Flask应用
        :param config: 配置对象
        :return: Flask应用
        """
        app = Flask(__name__)
        app.config.from_object(config) # 先从配置对象中加载默认配置信息
    
        # 从环境变量指向的配置文件中读取的配置信息会覆盖掉从配置对象中加载的同名参数
        app.config.from_envvar("ENV_SETTING", silent=True)
        return app
    
    class DefaultConfig(object):
        """默认配置"""
        SECRET_KEY = 'abcdefg'
    
    class DevelopmentConfig(DefaultConfig):
        DEBUG=True
    
    # app = create_flask_app(DefaultConfig)
    app = create_flask_app(DevelopmentConfig)
    
    @app.route("/")
    def index():
        print(app.config['SECRET_KEY'])
        return "hello world"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    app.run 参数

    指定运行的主机IP地址,端口,是否开启调试模式

    app.run(host="0.0.0.0", port=6000, debug = True)
    
    • 1

    2.4开发服务器启动方式

    方式一:新式的终端运行

    hello.py

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def hello_world():
        return "

    Hello, World!

    "
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    export FLASK_APP=hello
    flask run
    Running on http://127.0.0.1:5000/
    
    • 1
    • 2
    • 3
    • 环境变量 FLASK_APP 指明flask的启动实例

    • flask run -h 0.0.0.0 -p 8000 绑定地址 端口

    • flask run --help获取帮助

    • 生产模式与开发模式的控制
      通过FLASK_ENV环境变量指明
      export FLASK_ENV=production 运行在生产模式,未指明则默认为此方式
      export FLASK_ENV=development运行在开发模式

    方式二:Pycharm启动

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3.路由与蓝图

    1.路由

    1.查询路由信息

    方式1:命令行方式
    flask routes
    
    • 1
    Endpoint  Methods  Rule                       # Endpoint: 视图函数名字,Rule: 路径
    --------  -------  -----------------------
    index     GET      /
    static    GET      /static/
    
    • 1
    • 2
    • 3
    • 4
    • 在程序中获取
    print(app.url_map)
    
    • 1
    方式2:在程序读取路由信息
    for rule in app.url_map.iter_rules():
        print('name={} path={}'.format(rule.endpoint, rule.rule))
        # iter_rules返回一个列表
        # rule.endpoint视图的名字
        # rule.rule视图的路径
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以json的方式返回应用内的所有路由信息

     主视图,返回所有视图网址
        """
        rules_iterator = app.url_map.iter_rules()
        return json.dumps({rule.endpoint: rule.rule for rule in rules_iterator})
        # json.dumps()是把python对象转换成json对象的一个过程,生成的是字符串
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.指定请求方式

    • GET
    • OPTIONS(自带) -> 简介版的GET请求,用于询问服务器接口信息
    • HEAD(自带)

    cors跨域解决 ,前端访问后端接口时,先发一个options请求,后端允许请求,option是询问接口的特征的,不涉及真实的业务数据,比如接口的允许方式,允许的请求源头,然后浏览器发真才发真正的GET请求
    那django-cors是在中间件中拦截处理了option请求

    methods参数可以自己指定一个接口的请求方式

    @app.route("/hello", methods=["GET", "POST"])
    def view_func_2():
        return "hello"
    
    • 1
    • 2
    • 3

    2.蓝图

    • 一个应用可以具有多个Blueprint
    • 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/user”、“/goods”
    • Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的
    • 在一个应用初始化时,就应该要注册需要使用的Blueprint
    • 但是一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中

    1.使用方式,分三步

    • 单一文件中,蓝图对象与定义视图放到一个文件中
    from flask import Flask, Blueprint
    app = Flask(__name__)
    user_bp = Blueprint('user', __name__) # 1.创建一个蓝图对象
    
    @user_bp.route('/hello')  # 2.设置视图的时候,由蓝图对象的路由装饰器进行绑定
    def index():
        return "hello 444world"
    app.register_blueprint(user_bp, url_prefix='/user') # 3.在应用对象上注册这个蓝图对象
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    url_prefix表示需要访问的路径/hello前加一个前缀user ,访问的路径:
    http://127.0.0.1:5000/user/hello
    在这里插入图片描述

    • 目录(包)蓝图中使用

      新建一个目录goods, 通常将创建蓝图对象放到Python包的__init__.py文件中  
      
      • 1

    init.py

    from flask import Blueprint
    
    goods_bp = Blueprint('good', __name__)
    
    from . import view
    
    • 1
    • 2
    • 3
    • 4
    • 5

    view.py

    from . import goods_bp
    
    @goods_bp.route('/goods')
    def get_goods():
        return "get goods"
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    主程序文件中 注册蓝图

    from flask import Flask, Blueprint
    user_bp = Blueprint('user', __name__)
    app = Flask(__name__)
    @user_bp.route('/hello')
    def index():
        return "hello 4444world"
    app.register_blueprint(user_bp, url_prefix='/user')
    
    from goods import goods_bp
    app.register_blueprint(goods_bp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    目录结构
    在这里插入图片描述

    • 扩展用法
    app.register_blueprint(user_bp, url_prefix='/user') # url_prefix蓝图的前缀
    admin = Blueprint("admin",__name__,static_folder='static_admin')  # static_folder设置蓝图的静态目录
    admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib') # static_url_path是静态访问路径
    admin = Blueprint('admin',__name__,template_folder='my_templates') # template_folder蓝图内部模板目录
    
    • 1
    • 2
    • 3
    • 4

    4.请求与响应

    4.1. URL路径参数(动态路由)请求

    1.Flask提供的类型的转换器

    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    比如

    @app.route('/users/')
    def user_info(user_id):
        print(type(user_id))
        return 'hello user {}'.format(user_id)
    
    
    @app.route('/users/')
    def user_info(user_id):
        print(type(user_id))
        return 'hello user {}'.format(user_id)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.自定义转换器

    1.创建转换器类,保存匹配时的正则表达式
    from werkzeug.routing import BaseConverter
    
    class MobileConverter(BaseConverter):
        """
        手机号格式
        """
        regex = r'1[3-9]\d{9}'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2. 自定义的转换器告知Flask应用
    # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: mobile
    app.url_map.converters['mobile'] = MobileConverter
    
    • 1
    • 2
    3.在使用转换器的地方定义使用
    @app.route(('/send_code/'))
    def get_mobile(mobile_num):
         return "get mobile number:{}".format(mobile_num)
    
    • 1
    • 2
    • 3

    3. 其它的参数请求

    不同位置的参数都存放在request的不同属性中

    属性说明类型
    data记录请求的数据,并转换为字符串*
    form记录请求中的表单数据MultiDict
    args记录请求中的查询参数MultiDict
    cookies记录请求中的cookie信息Dict
    headers记录请求中的报文EnvironHeaders
    method记录请求使用的HTTP方法GET/POST
    url记录请求的URL地址string
    files记录请求上传的文件*
    • 实例1.想要获取请求/user?channel=123456666中channel的参数
    from flask import Flask,request
    app=Flask(__name__)
    
    @app.route('/user')
    def get_user():
         channel = request.args.get('channel')
         return "get user id {}".format(channel)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果
    在这里插入图片描述

    • 实例2.上传图片
    from flask import Flask,request
    
    app=Flask(__name__)
    
    @app.route('/upload', methods=['POST'])
    def upload_image():
         f = request.files['picture']
         with open('./img.jpg', 'wb') as new_jpg:
              new_jpg.write(f.read())
    
         return 'ok'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    postman测试,如下图
    在这里插入图片描述
    flask给我们封装了一个save方法 不需要with open方法

    from flask import Flask,request
    
    app=Flask(__name__)
    
    @app.route('/upload', methods=['POST'])
    def upload_image():
         f = request.files['picture']
         # with open('./img.jpg', 'wb') as new_jpg:
         #      new_jpg.write(f.read())
         f.save('./image.jpg')
         return 'ok'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.2.处理响应

    在不同的场景里返回不同的响应信息

    1 使用render_template方法渲染模板并返回

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    模板html内容
    <h1>{{ user_name }}</h1>
    <h1>{{ user_id}}</h1>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如图 templates模板文件夹下新建的一个index.html
    在这里插入图片描述

    后端视图

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        username = 'zhangsan'
        userid = 12
        return render_template('index.html', user_name=username, user_id=userid)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    扩展:后面视图这样也可以

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        data = {'user_name':'zhangsan', 'user_id':12}
        # return render_template('index.html', user_name=username, user_id=userid)
        return render_template('index.html', **data)
        # **data等价于 user_name='zhangsan', user_id=12
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.重定向

    from flask import redirect
    
    @app.route('/demo2')
    def demo2():
        return redirect('http://www.baidu.com')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.返回JSON

    • json.dumps() 仅仅是把数据转换为json格式
    • jsonify 1.转换成json格式字符串,设置了响应头Content-Type:application/json
    from flask import jsonify
    
    @app.route('/demo3')
    def demo3():
        json_dict = {
            "user_id": 10,
            "user_name": "laowang"
        }
        return jsonify(json_dict)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4 自定义状态码和响应头

    1.元组方式

    元组必须是 (response, status, headers) 的形式

    @app.route('/article')
    def demo4():
        # return 'hello world 666', 560
        # return 'hello world 666', 560, [('user_name', 'lisi')]
        return 'hello world 666', 560, {'user_name': 'lisi'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2. make_response方式
    @app.route('/article2')
    def demo5():
        resp = make_response('make response测试')
            resp.headers[“user_name”] = “zhangsan”
            resp.status =404 not found”
        return resp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.3.Cookie与Session

    1.Cookie

    • 设置
    from flask import Flask, make_response
    
    app = Flask(__name__)
    
    @app.route('/cookie')
    def set_cookie():
        resp = make_response('set cookie ok')
        resp.set_cookie('username', 'wangwu')
        return resp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    浏览器里查看设置的信息
    在这里插入图片描述

    • 设置有效期
    from flask import Flask, make_response
    
    app = Flask(__name__)
    
    @app.route('/cookie')
    def set_cookie():
        resp = make_response('set cookie ok')
        resp.set_cookie('username', 'wangwu', max_age=3600)
        return resp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 读取
    from flask import request
    
    @app.route('/get_cookie')
    def get_cookie():
        resp = request.cookies.get('username')
        return resp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 删除
    from flask import request
    
    @app.route('/delete_cookie')
    def delete_cookie():
        response = make_response('hello world')
        response.delete_cookie('username')
        return response
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.Session

    • 需要先设置SECRET_KEY
    class DefaultConfig(object):
        SECRET_KEY = 'ddkslslgcd;slslgdd 98877777dds'
    
    app.config.from_object(DefaultConfig)
    
    或者直接设置
    app.secret_key='ddkslslgcd;slslgdd 98877777dds'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 设置
    @app.route('/set_session')
    def set_session():
        session['username'] = 'lisi'
        return 'ok'
    
    • 1
    • 2
    • 3
    • 4
    • 读取
    @app.route('/get_session')
    def get_session():
        username = session.get('username')
        return 'get session username:{}'.format(username)
    
    • 1
    • 2
    • 3
    • 4

    5.异常、请求勾子与上下文

    5.1.异常处理

    1.HTTP 异常主动抛出

    • abort 方法
    abort(404)  # 抛出状态码的话,只能抛出 HTTP 协议的错误状态码
    
    • 1

    2.捕获错误

    • errorhandler 装饰器
      注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法
    @app.errorhandler(ZeroDivisionError)
    def zero_division_error(e):
        return '除数不能为0'
    
    • 1
    • 2
    • 3
    @app.errorhandler(500)
    def internal_server_error(e):
        return '服务器搬家了'
    
    
    • 1
    • 2
    • 3
    • 4

    5.2.请求钩子

    请求钩子就是起到中间件或者中间层的作用
    假如有多个中间层,每个中间层可以理解为一个类,当一个具体的请求过来是,先去找中间件,DJANGO的处理过程

    # [ middleware1  ->  Class Middleware1
    #                         def pre_process
    #                         def after_process(response)
    # middleware2
    # middleware3]
    # 请求的处理过程  pre_process  -> view -> after_process
    # request 请求支持 处理流程
    # middleware1.pre_process() -> middleware2.pre_process() -> middleware3.pre_process()
    # -> view() -> middleware3.after_process() -> middleware2.after_process() -> middleware1.after_process() -> client
    # 中间件处理 不区分具体是哪个视图 ,对所有视图通通生效
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Flask支持如下四种请求钩子

    • before_first_request
      在处理第一个请求前执行

    • before_request
      在每次请求前执行
      如果在某修饰的函数中返回了一个响应,视图函数将不再被调用

    • after_request
      如果没有抛出错误,在每次请求后执行
      接受一个参数:视图函数作出的响应
      在此函数中可以对响应值在返回之前做最后一步修改处理
      需要将参数中的响应在此参数中进行返回

    • teardown_request:
      在每次请求后执行
      接受一个参数:错误信息,如果有相关错误抛出

    代码测试

    from flask import Flask
    from flask import abort
    app = Flask(__name__)
    
    # 在第一次请求之前调用,可以在此方法内部做一些初始化操作
    @app.before_first_request
    def before_first_request():
        print("before_first_request")
    
    
    # 在每一次请求之前调用,这时候已经有请求了,可能在这个方法里面做请求的校验
    # 如果请求的校验不成功,可以直接在此方法中进行响应,直接return之后那么就不会执行视图函数
    @app.before_request
    def before_request():
        print("before_request")
        # if 请求不符合条件:
        #     return "laowang"
    
    
    # 在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入,可以在此方法中对响应做最后一步统一的处理
    @app.after_request
    def after_request(response):
        print("after_request")
        response.headers["Content-Type"] = "application/json"
        return response
    
    
    # 请每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
    @app.teardown_request
    def teardown_request(response):
        print("teardown_request")
    
    
    @app.route('/')
    def index():
        print('view 视图已执行')
        return 'index'
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    5.3.上下文

    Flask中有两种上下文,请求上下文和应用上下文

    Flask中上下文对象:相当于一个容器,保存了 Flask 程序运行过程中的一些信息。

    1 请求上下文(request context)

    • request
      封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get(‘user’),获取的是get请求的参数。
    • session
      用来记录请求会话中的信息,针对的是用户信息。举例:session[‘name’] = user.id,可以记录用户信息。还可以通过session.get(‘name’)获取用户信息。

    2 应用上下文(application context)

    它的字面意思是 应用上下文,但它不是一直存在的,它只是request context 中的一个对 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而生,随 request 而灭的

    2.1.current_app
    # 导入Flask类
    from flask import Flask, current_app
    
    #Flask类接收一个参数__name__
    app = Flask(__name__, static_url_path='/w', static_folder='static_file')
    app.redis_cli='redis-cli 888'
    
    # 装饰器的作用是将路由映射到视图函数index
    #定义视图
    @app.route('/')
    def index():
        return  current_app.redis_cli
    
    if __name__ == '__main__':
        app.run()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    2.2.g对象

    g 作为 flask 程序全局的一个临时变量,充当中间媒介的作用,我们可以通过它在一次请求调用的多个函数间传递一些数据。每次请求都会重设这个变量。

    示例

    from flask import Flask, g
    
    app = Flask(__name__)
    
    def db_query():
        user_id = g.user_id
        user_name = g.user_name
        print('user_id={} user_name={}'.format(user_id, user_name))
    
    @app.route('/')
    def get_user_profile():
        g.user_id = 123
        g.user_name = 'itcast'
        db_query()
        return 'hello world'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    g对象与请求钩子的综合案例

    from flask import Flask, abort, g
    
    app = Flask(__name__)
    
    @app.before_request
    def authentication():
        """
        利用before_request请求钩子,在进入所有视图前先尝试判断用户身份
        :return:
        """
        # TODO 此处利用鉴权机制(如cookie、session、jwt等)鉴别用户身份信息
        # if 已登录用户,用户有身份信息
        g.user_id = 123
        # else 未登录用户,用户无身份信息
        # g.user_id = None
    
    def login_required(func):
        def wrapper(*args, **kwargs):
            if g.user_id is not None:
                return func(*args, **kwargs)
            else:
                abort(401)
    
        return wrapper
    
    @app.route('/')
    def index():
        return 'home page user_id={}'.format(g.user_id)
    
    @app.route('/profile')
    @login_required
    def get_user_profile():
        return 'user profile page user_id={}'.format(g.user_id)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    2.3.app_context 与 request_context
    • app_context
      app_context为我们提供了应用上下文环境,允许我们在外部使用应用上下文current_app、g
      可以通过with语句进行使用
    >>> from flask import Flask
    >>> app = Flask('')
    >>> app.redis_cli = 'redis client'
    >>> 
    >>> from flask import current_app
    >>> current_app.redis_cli   # 错误,没有上下文环境
    报错
    >>> with app.app_context():  # 借助with语句使用app_context创建应用上下文
    ...     print(current_app.redis_cli)
    ...
    redis client
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • request_context
      request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文request、session
      可以通过with语句进行使用
    >>> from flask import Flask
    >>> app = Flask('')
    >>> request.args  # 错误,没有上下文环境
    报错
    >>> environ = {'wsgi.version':(1,0), 'wsgi.input': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'SERVER_NAME': 'itcast server', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80'}  # 模拟解析客户端请求之后的wsgi字典数据
    >>> with app.request_context(environ):  # 借助with语句使用request_context创建请求上下文
    ...     print(request.path)
    ...   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    python打包exe
    云服务多语言 SDK
    每日三题 8.22
    [尚硅谷React笔记]——第1章 React简介
    JAVA JDBC使用PreparedStatement实现CRUD操作
    设计模式学习笔记(十)装饰器模式及其应用
    ncurses库意外失联引发的思考
    Java面试题一
    Vuex学习笔记
    Python小游戏——小鸟管道游戏【含完整源码】
  • 原文地址:https://blog.csdn.net/xiangfengl/article/details/128192221