美文网首页Py进阶@IT·互联网程序员
# Flask框架之视图和路由

# Flask框架之视图和路由

作者: 懵懂_傻孩纸 | 来源:发表于2018-09-19 17:41 被阅读120次

    HelloWord程序

    创建Python项目

    • 打开Pycharm,创建 pure Python类型的项目,创建项目完成之后选择之前创建的py3_flask作为虚拟环境


      image.png

    第四步路径可以通过在指定的虚拟环境下,输入 which python获得

    示例

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    第一行:导入Flask类
    第三行:Flask函数接收一个参数name,他会指向程序所在的包
    第六行:装饰器的作用是将路由映射到试图函数hello_word
    第十一、十二行: Flask应用程序实例的run方法,启动WEB服务器

    在程序运行过程中,程序实例会使用url_map将装饰器路由和视图的对应关系保存起来


    相关参数配置

    在上一节实现了一个最简单的 Flask 应用程序,只使用了7行代码,接来对 Flask 程序的创建,运行配置做进一步的了解,具体有:

    • Flask 程序初始化参数
    • Flask 程序相关配置加载方式
    • app.run() 参数

    初始化参数

    Flask 程序实例在创建的时候,需要默认传入当前 Flask 程序所指定的包(模块),接下来就来详细查看一下 Flask 应用程序在创建的时候一些需要我们关注的参数:


    image.png
    • import_name
      • Flask程序所在的包(模块),传 name 就可以
      • 其可以决定 Flask 在访问静态文件时查找的路径
    • static_path
      • 静态文件访问路径(不推荐使用,使用 static_url_path 代替)
    • static_url_path
      • 静态文件访问路径,可以不传,默认为:/ + static_folder
    • static_folder
      • 静态文件存储的文件夹,可以不传,默认为 static
    • template_folder
      • 模板文件存储的文件夹,可以不传,默认为 templates

    程序加载配置

    在 Flask 程序运行的时候,可以给 Flask 设置相关配置,比如:配置 Debug 模式,配置数据库连接地址等等,设置 Flask 配置有以下三种方式:

    • 从配置对象中加载(常用)
      • app.config.from_object()
    • 从配置文件中加载
      • app.config.from_pyfile()
    • 从环境变量中加载(了解)
      • app.config.from_envvar()

    使用方式

    示例:

    from flask import Flask
    
    
    # 1.自定义项目配置类
    class Config(object):
        '''flask项目的配置信息,以类属性的形式罗列即可'''
        DEBUG = True
    
    
    app = Flask(__name__)
    
    # 方式一:使用类的方式加载项目配置信息
    # 2.加载配置类
    # app.config.from_object(Config)
    # 方式二:使用文件链接方式加载项目配置信息
    # app.config.from_pyfile('config.ini')
    # 方式三:使用环境变量方式
    app.config.from_envvar('FLASKCONFIG')
    
    
    # 常用的项目配置属性也会在App中保留一份
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word '
    
    
    if __name__ == '__main__':
        app.run()
    
    

    配置对象

    • 从配置对象中加载,创建配置的类,代码如下:
    # 配置对象,里面定义需要给 APP 添加的一系列配置
    class Config(object):
        DEBUG = True
    
    
    # 创建 Flask 类的对象,指向程序所在的包的名称
    app = Flask(__name__)
    
    # 从配置对象中加载配置
    app.config.from_object(Config)
    

    运行测试,在修改代码后直接保存,会自动重启服务器

    配置文件

    • 创建配置文件 config.ini,在配置文件中添加配置


      image.png
    • 使用代码去加载配置

    # 创建 Flask 类的对象,指向程序所在的包的名称
    app = Flask(__name__)
    
    # 从配置文件中加载配置
    app.config.from_pyfile('config.ini')
    

    环境变量(了解)

    • 编辑运行的相关配置


      image.png
      image.png
    • 使用代码去加载
    # 创建 Flask 类的对象,指向程序所在的包的名称
    app = Flask(__name__)
    # 加载指定环境变量名称所对应的相关配置
    app.config.from_envvar('FLASKCONFIG')
    

    读取配置

    • app.config.get()
    • 在视图函数中使用 current_app.config.get()
    @app.route('/')
    def hello_word():
    
        # 获取属性值
        print(app.config['DEBUG'])
        # 当DEBUG写错时,显示后面的提示信息
        print(app.config.get('DEBUG','AA'))
        return 'Hello Word '
    

    注:Flask 应用程序将一些常用的配置设置成了应用程序对象的属性,也可以通过属性直接设置/获取某些配置:app.debug = True


    路由基本定义

    • 明确路由定义的参数,请求方式指定
    • PostMan使用

    指定路由地址

    # 指定访问路径为 demo1
    @app.route('/demo1')
    def demo1():
        return 'demo1'
    

    给路由传参实列

    有时我们需要将同一类URL映射到同一个视图函数处理,比如:使用同一个视图函数来显示不同用户的个人信息

    # 路由传递参数
    @app.route('/user/<user_id>')
    def user_info(user_id):
        return 'hello %s' % user_id
    
    • 路由传递的参数默认当作string处理,也可以指定参数的类型
    # 路由传递参数
    @app.route('/user/<int:user_id>')
    def user_info(user_id):
        return 'hello %d' % user_id
    

    这里指定int,尖括号中的内容是动态的,在此暂时可以理解为接受int类型的值,实际上int代表使用integerConverter去处理url传入的参数

    指定请求方式

    在Flask中,定义一个路由,默认的请求方式为:

    • GET
    • OPTIONS(自带)
    • HEAD(自带)
      如果想添加请求方式,那么可以如下指定
    @app.route('/demo2', methods=['GET', 'POST'])
    def demo2():
        # 直接从请求中取到请求方式并返回
        return request.method
    

    完整代示例:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    # 127.0.0.1/demo1
    @app.route('/demo1')
    def demo1():
        return 'demo1'
    
    
    # 给路由传参
    # 127.0.0.1:5000/user/str数据类型
    # <user_id>转换器提取url路径的参数
    @app.route('/user/<user_id>')
    def demo2(user_id):
        return 'user %s' % user_id
    
    
    # 127.0.0.1:5000/user_int/int数据类型
    @app.route('/user_int/<int:user_id>')
    def demo3(user_id):
        return 'user %d' % user_id
    
    
    if __name__ == '__main__':
        print(app.url_map)
        app.run(debug=True)
        
    

    正则匹配路由

    在 web 开发中,可能会出现限制用户访问规则的场景,那么这个时候就需要用到正则匹配,根据自己的规则去限定请求参数再进行访问

    具体实现步骤为:

    • 导入转换器基类:在Flask中,所有的路由的匹配规则都是使用转换器独享记录
    • 自定义转换器:自定义类继承与转换器基类
    • 添加转换器到默认的转换器字典中
    • 使用自定义转化器实现自定义匹配规则

    代码实现

    • 导入转换器基类
    from werkzeug.routing import BaseConverter
    
    • 自定义转换器
    # 自定义正则转换器
    class RegexConverter(BaseConverter):
        def __init__(self, url_map, *args):
            super(RegexConverter, self).__init__(url_map)
            # 将接受的第1个参数当作匹配规则进行保存
            self.regex = args[0]
    
    • 添加转换器到默认的转换器字典中,并指定转换器使用时名字为: re
    app = Flask(__name__)
    
    # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
    app.url_map.converters['re'] = RegexConverter
    
    • 使用转换器去实现自定义匹配规则
      • 当前此处定义规则是:3位数字
    @app.route('/user/<re("[0-9]{3}"):user_id>')
    def user_info(user_id):
        return "user_id 为 %s" % user_id
    
    

    运行测试:http://127.0.0.1:5000/user/123 ,如果访问的url不符合规则,会提示找不到页面

    系统自带转换器

    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }
    

    系统自带的转换器具体使用方式在每种转换器的注释代码中有写,请留意每种转换器初始化的参数。

    完整代码示例

    
    from flask import Flask
    # 导入转换器基类
    from werkzeug.routing import BaseConverter
    
    app = Flask(__name__)
    
    
    # 1.自定义转换器类
    class RegexConverter(BaseConverter):
        # 重写regex属性,当你将正则表达式传入给他的时候,BaseConVerter类处理
        def __init__(self, url_map, re):
            # 1.初始化父类的init方法,完成正则定义注册工作
            super(RegexConverter, self).__init__(url_map)
            # 2.初始化子类的init方法
            self.regex = re
    
    
    # 2.注册正则匹配类
    app.url_map.converters['re'] = RegexConverter
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    # 127.0.0.1:5000/user/123456
    # 3.使用自定义正则转换器
    
    @app.route('/user/<re("[0-9]{6}"):user_id>')
    def demo1(user_id):
        return 'user %s' % user_id
    
    
    if __name__ == '__main__':
        app.run(debug=True)
        
        
    

    获取请求参数

    • request:flask中代表当前请求的 request 对象
    • 作用:在视图函数中取出本次请求数据
    • 导入:from flask import request
      常用属性如下:
    属性 说明 类型
    data 记录请求的数据,并转换为字符 *
    form 记录请求中的表单数据 MultiDict
    args 记录请求中的查询参数 MultiDict
    cookies 记录请求中的cookie信息 Dict
    headers 记录请求中的报文头 EnvironHeaders
    method 记录请求使用的HTTP方法 GET/POST
    url 记录请求的URL地址 string
    files 记录请求上传的文件 *

    完整代码

    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    '''
    get: 获取服务器数据,问号后面携带的参数,告知服务器获取的数据
    post: 往服务器新增数据,请求体里面携带的参数:一般是需要存到数据库的数据
    '''
    
    
    # 127.0.0.1:5000/get?user_name=curry&age=18
    @app.route('/get')
    def demo1():
        """提取get请求问号后面携带的参数"""
        # request.method   获取访问方式:后面字符串必须大写
        if request.method == 'GET':
            # 方式: request.method.args.get('key',"")
            user_name = request.args.get('user_name', '')
            age = request.args.get('age', '')
            return '%s %s' % (user_name, age)
        else:
            return '405请求方式不正确'
    
    
    @app.route('/post', methods=['post'])
    def demo2():
        '''提取post请求体中携带的参数'''
        if request.method == 'POST':
            # 方式
            user_name = request.form.get('user_name', '')
            user_id = request.form.get('user_id', '')
            return '%s %s' % (user_name, user_id)
        else:
            return '405请求方式不正确'
    
    @app.route('/upload', methods=['post'])
    def demo3():
    
        if request.method == 'POST':
            # 方式:request.files.get('key', '')
            file = request.files.get('pic', '')
            file.save('./1.jpg')
            return 'upload succes'
        else:
            return '405请求方式不正确'
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    

    构造响应数据

    视图常用逻辑

    • 返回JSON
    • 重定向
      • Url_for
    • 自定义状态码

    返回JSON

    在使用Flask写一个接口时候需要给客户端返回JSON数据,在Flask中可以直接使用jsonify生成一个JSON的响应

    # 返回JSON
    @app.route('/demo3')
    def demo3():
        json_dict = {
            "user_id": 10,
            "user_name": "laowang"
        }
        return jsonify(json_dict)
    
    

    不推荐使用json.dumps转成JSON字符串直接返回,因为返回的数据要符合HTTP协议规范,如果是JSON需要指定content-type:application/json
    完整代码:

    from flask import Flask, jsonify
    import json
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    @app.route('/json')
    def demo1():
        '''json数据转换'''
    
        dict = {
            'name': 'james',
            'age': 34,
            'info': {
                'team': 'laker'
            }
        }
        # 序列化: 将python对象转换成json字符串
        json_str = json.dumps(dict)
        # 反序列化: 将json字符串转换成python对象
        my_json = json.loads(json_str)
    
        # 1.能将python对象转换成json字符串
        # 2.能将相应体数封装成响应对象并返回
        # 3.指明了响应数据格式: ContentType = 'application/json'
        my_jsons = jsonify(dict)
        return my_jsons
        # return json_str
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    
    

    重定向

    • 重定向到百度
    # 重定向
    @app.route('/demo4')
    def demo4():
        return redirect('http://www.baidu.com')
    
    • 重定向到自己写的视图函数
      • 可以直接填写自己的Url路径
      • 也可以使用url_for生成指定试图函数所对应的url
    @app.route('/demo1')
    def demo1():
        return 'demo1'
    
    # 重定向
    @app.route('/demo4')
    def demo4():
        return redirect(url_for('demo1'))
    
    • 重定向到带有参数的视图函数
      • 在url_for函数中传入参数
    # 路由传递参数
    @app.route('/user/<user_id>')
    def user_info(user_id):
        return 'hello %d' % user_id
    
    # 重定向
    @app.route('/demo4')
    def demo4():
        # 使用 url_for 生成指定视图函数所对应的 url
        return redirect(url_for('user_info', user_id=100))
    

    完整代码:

    from flask import Flask, redirect, url_for
    
    app = Flask(__name__)
    
    
    @app.route('/index')
    def hello_word():
        return 'Hello Word'
    
    
    @app.route('/redirect')
    def redirects():
        '''重定向到百度'''
        # 使用redirect方法进行重定向
        return redirect('http://www.baidu.com')
    
    
    @app.route('/demo2')
    def demo2():
        '''重定向到自身的根路径'''
    
        # url_for : url反向解析函数
        # 根据函数名称一一解析出对应的url
        return redirect(url_for('hello_word'))
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    

    自定义状态码

    • 在Flask中,可以很方便的返回自定义状态码,以实现不符合http协议的状态码,例如: status code:666
    @app.route('/demo4')
    def demo4():
        return '状态码为 666', 666
    

    装饰器路由具体实现梳理

    image.png
    • Flask有两大核心:Werkzeug和Jinja2
      • Werkzeug实现路由\调试和web服务器网关接口
      • Jinja2实现了模板

    • Werkzeug是一个遵循WSGI协议的python函数库
      • 其内部实现了很多Web框架底层的东西,比如request和response对象;
      • 与WSGI规范的兼容;支持Unicode;
      • 支持基本的会话管理和签名Cookie;
      • 集成URL请求路由等。

    • Werkzeug库的 routing 模块负责实现 URL 解析。不同的 URL 对应不同的视图函数,routing模块会对请求信息的URL进行解析,匹配到URL对应的视图函数,执行该函数以此生成一个响应信息。


      routing模块内部有:
    • Rule类
      • 用来构造不同的URL模式的对象,路由URL规则
    • Map类
      • 存储所有的URL规则和一些配置参数
    • BaseConverter的子类
      • 负责定义匹配规则
    • MapAdapter类
      • 负责协调Rule做具体的匹配的工作

    状态保持

    • 因为http是一种无状态协议,浏览器请求服务器是无状态的。
    • 无状态:指一次用户请求时,浏览器\服务器无法知道之前这个用户做过什么,每次请求都是新的请求
    • 无状态原因:浏览器与服务器之间是使用socket套接字进行通信,服务器将请求结果返回给浏览器之后,会关闭当前的socket连接,而且服务器也会在处理页面完毕之后销毁页面对象
    • 有时需要保持下来用户浏览的状态,比如用户是否登陆过,浏览过哪些商品等
    • 实现状态保存主要有两种方式
      • 在客户端保存用cookie
      • 在服务端保存用session

    无状态协议

    1.协议对于事务处理没有记忆能力
    2.对同一个 url 请求没有上下文关系
    3.每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
    4.服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器
    5.人生若只如初见

    Cookie

    • Cookie:指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地的数据(通常经过加密)。

      • 复数形式Cookies.
      • Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。
      • Cookie的key/value可以由服务器端自己定义。
    • 提示:

      • Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
        -Cookie基于域名安全,不同域名的Cookie是不能互相访问的
        • 如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息
        • 浏览器的同源策略
      • 当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息

    设置cookie

    from flask imoprt Flask,make_response
    @app.route('/cookie')
    def set_cookie():
        resp = make_response('this is to set cookie')
        resp.set_cookie('username', 'itcast')
        return resp
    
    image.png

    设置过期时间

    @app.route('/cookie')
    def set_cookie():
        response = make_response('hello world')
        response.set_cookie('username', 'itheima', max_age=3600)
        return response
    
    image.png

    获取cookie

    from flask import Flask,request
    #获取cookie
    @app.route('/request')
    def resp_cookie():
        resp = request.cookies.get('username')
        return resp
    
    image.png

    完整代码:

    from flask import Flask, make_response, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    @app.route('/login')
    def login():
        '''登录成功后借助cookie保存登录信息'''
        # 1.创建响应对象
        response = make_response('login success')
        # 2.借助响应对象的set_cookie方法设置键值对
        '''
        参数1: key   参数2: value  参数3: max_age = 表示过期时长
        '''
        response.set_cookie('user_name', 'laowang', max_age=3600)
        response.set_cookie('user_id', '1', max_age=3600)
    
        return response
    
    
    @app.route('/index')
    def index():
        '''再次请求首页的时候,提起cookie中的用户信息'''
        user_name = request.cookies.get('user_name', '')
        user_id = request.cookies.get('user_id', '')
    
        return 'index %s  --  %s' % (user_name, user_id)
    
    
    @app.route('/login_out')
    def loginout():
        '''退出登录删除cookie中用户数据'''
        # 1.构建响应对象
        respone = make_response('login out delete')
        # 2.利用响应对象中的delete_cookie方法删除对应的cookie
        respone.delete_cookie('user_name')
        respone.delete_cookie('user_id')
        return respone
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    

    Session

    • 对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
    • 在服务器端进行状态保持的方案就是Session
    • Session依赖于Cookie

    session数据的获取

    session:请求上下文对象,用于处理HTTP请求中的一些数据内容

    @app.route('/set_session')
    def set_session():
        session['username'] = 'itcast'
        return 'set_session ok!'
    
    @app.route('/get_session')
    def get_session():
        return session.get('username')
    

    记得设置secret_key: app.secret_key = 'password' 的作用
    https://segmentfault.com/q/1010000007295395

    完整代码:

    from flask import Flask, session
    
    app = Flask(__name__)
    
    # 加密
    app.secret_key = 'asdfghjkl'
    
    
    @app.route('/')
    def hello_word():
        return 'Hello Word'
    
    
    @app.route('/login')
    def login():
        '''登录成功借助cookie储存用户登录信息到服务器'''
        # session 会将用户数据存储到服务器中,一般是数据库
        session['user_name'] = 'laosong'
        session['user_id'] = '1'
        return 'login sucess'
    
    
    @app.route('/index')
    def index():
        '''再次请求首页的时候可以借助session提取用户的登录信息'''
        user_name = session.get('user_name')
        user_id = session.get('user_id')
    
        return 'user_name : %s, user_id : %s' % (user_name, user_id)
    
    
    @app.route('/out')
    def login_out():
        '''退出后删除'''
        session.pop('user_name', '')
        session.pop('user_id', '')
        return 'out susser'
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    
    

    请求钩子

    在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:

    • 在请求开始时,建立数据库连接;
    • 在请求开始时,根据需求进行权限校验;
    • 在请求结束时,指定数据的交互格式;

    为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。

    请求钩子是通过装饰器的形式实现,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(e):
        print("teardown_request")
    
    
    @app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    • 在第一次请求时打印

    before_first_request
    before_request
    after_request
    teardown_request

    • 在第二次请求时打印

    before_request
    after_request
    teardown_request


    异常捕获

    HTTP异常主动抛出

    • abort 方法
      • 抛出一个给定状态的HTTPException 或者 指定响应, 例如想要用一个页面未找到异常来终止请求,可以调用abort(404)
    • 参数
      • code-HTTP的错误状态码(必须)
    # abort(404)
    abort(500)
    

    抛出状态码的话,只能抛出 HTTP 协议的错误状态码

    捕获错误

    • errorhandler装饰器
      • 注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法
    • 参数
      • code_or_exception-HTTP的错误状态码或指定异常
    • 例如统一处理状态码为500的错误给用户友好提示:
    @app.errorhandler(500)
    def internal_server_error(e):
        return '服务器搬家了'
    
    • 捕获指定异常
    @app.errorhandler(ZeroDivisionError)
    def zero_division_error(e):
        return '除数不能为0'
    

    完整代码:

    from flask import Flask, redirect, abort
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_word():
        # 定义两个错误
        # a = 1/0
        # abort 指定错误
        abort(404)
        return 'Hello Word'
    
    
    @app.errorhandler(404)
    def handler(e):
        '''404'''
        print(e)
        # 重定向
        return redirect('http://hd.mi.com/webfile/zt/hd/2014042802/cn.html')
    
    
    @app.errorhandler(ZeroDivisionError)
    def error(a):
        '''捕获异常'''
        return '不能除零'
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    
    

    上下文

    上下文:即语境,语意,在程序中可以理解为在代码执行到某一时刻时,根据之前代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情。

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

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

    请求上下文(request context)

    在 flask 中,可以直接在视图函数中使用 request 这个对象进行获取相关数据,而 request 就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session

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

    应用上下文(application context)

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

    应用上下文对象有:current_app,g

    current_app

    应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

    • 应用的启动脚本是哪个文件,启动时指定了哪些参数
    • 加载了哪些配置文件,导入了哪些配置
    • 连了哪个数据库
    • 有哪些public的工具类、常量
    • 应用跑再哪个机器上,IP多少,内存多大
    current_app.name
    current_app.test_value='value'
    

    g变量

    g 作为 flask 程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别

    g.name='abc'
    

    不同的请求,会有不同的全局变量

    两者区别:

    • 请求上下文:保存了客户端和服务器交互的数据
    • 应用上下文:flask 应用程序运行过程中,保存的一些配置信息,比如程序名、数据库连接、应用信息等

    上下文中的对象只能在指定上下文中使用,超出范围不能使用 请求上下文和应用上下文原理实现:https://segmentfault.com/a/1190000004223296

    完整代码

    from flask import Flask, request, session, current_app, g
    
    app = Flask(__name__)
    
    app.secret_key = 'asdfghjkl'
    
    
    @app.route('/')
    def hello_word():
    
        # 请求上下文
        print(request.method)
        print(request.url)
        session['user_name'] = 'curry'
        print(session.get('user_name', ''))
    
        # 应用上下文
        current_app.config.get("DEBUG")
        g.user = 'James'
        print(g.user)
    
        return 'Hello Word'
    
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    Flask-script扩展

    通过使用Flask-Script扩展,我们可以在Flask服务器启动的时候,通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参,比如我们可以通过:

    python hello.py runserver -host ip地址
    以上代码告诉服务器在哪个网络接口监听来自客户端的连接。默认情况下,服务器只监听来自服务器所在的计算机发起的连接,即localhost连接。

    我们可以通过python hello.py runserver --help来查看参数。


    image.png

    代码实现

    • 安装Flask-Script

    pip install flask-script

    • 集成Flask-Script
    from flask import Flask
    from flask_script import Manager
    
    app = Flask(__name__)
    # 把 Manager 类和应用程序实例进行关联
    manager = Manager(app)
    
    @app.route('/')
    def index():
        return '床前明月光'
    
    if __name__ == "__main__":
        manager.run()
    

    Flask-Script 还可以为当前应用程序添加脚本命令,后续项目中会使用到

    相关文章

      网友评论

        本文标题:# Flask框架之视图和路由

        本文链接:https://www.haomeiwen.com/subject/rrhvnftx.html