Flask 笔记

Flask 笔记

一、Flask介绍

1、学习Flask框架的原因

在这里插入图片描述

2020 Python 开发者调查结果显示Flask和Django是Python Web开发使用的最主要的两个框架。

2、Flask介绍

​ Flask诞生于2010年,是Armin ronacher用Python 语言基于Werkzeug工具箱编写的轻量级Web开发框架。

​ Flask本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现比如可以用Flask扩展加入ORM,窗体验证工具,文件上传、身份验证等。Flask没有默认使用的数据库,可以选择MySQL或NoSQL。

​ 其WSGI工具箱采用Werkzeug(路由模块),模板引擎使用Jinja2。这两个是Flask框架的核心。

Werkzeug是一个综合的WSGI Web应用程序库。它最初的WSGI应用程序的各种实用程序的简单集合,现已成为最先进的WSGI实用程序库之一。

Flask包装类Werkzeug,使用它来处理WSGI的细节,同时为定义强大的应用程序提供更多的结构和模式。

from werkzeug.wrappers import Request, Response@Request.application
def application(request):return Response('Hello, World!')if __name__ = '__main__':form werkzeug.serving import run_simplerun_simple('localhost', 5000, application)

Werkzeug包括:

  • 一个交互式调试器,允许实用堆栈中任何帧的交互式解释器在浏览器中检测堆栈跟踪和源代码
  • 一个功能齐全的请求对象,其中包含与标头、查询参数、表单数据、文件和cookie交互的对象。
  • 一个可以包装其他WSIG应用程序并处理流数据的响应对象。
  • 用于将URL与端点匹配并为端点生成URL的路由系统,具有用于从URL捕获变量的可扩展系统。
  • 用于处理实体标签、缓存控制、日期、用户代理、cookie、文件等HTTP实用程序。
  • 在本地开发应用程序时使用的线程化WSGI服务器。
  • 用于在测试期间模拟HTTP请求而不需要运行服务器的测试客户端。

Werkzeug可以识别Unicode,并且不强制执行任何依赖项。开发人员可以选择模板引擎、数据库适配器、甚至如何处理请求。它可用于构建各种最终用户应用程序,例如博客、维基或公告板。

3、框架对比

  1. 框架轻重
    • 重量级框架:为方便业务程序的开发,提供了丰富的工具、组件。如:Django
    • 轻量级框架:只提供Web框架的核心功能,自由、灵活、高度定制。如:Flask、Tornado
  2. 与Django对比
    • Django-admin:快速创建项目工程目录
    • manage.py:管理项目工程
    • orm模型:数据抽象层
    • admin:后台管理站点
    • 缓存机制
    • 文件存储系统
    • 用户认证系统

问题:

  1. Django与Flask谁好?对比一下两个框架?

    只有更合适->轻重对比->框架选择上,自由、灵活、高度定制选择Flask,快速实现业务、不考虑技术选型、越简单直接越好选择Django。

4、常用扩展包

扩展列表:http://flask.pocoo.org/extensions/

  • Flask-SQLalchemy:操作数据库
  • Flask-script:插入脚本
  • Flask-migrate:管理迁移数据库
  • Flask-Session:Session存储方式指定
  • Flask-WTF:表单
  • Flask-Mail:邮件
  • Flask-Bable:提供国际化和本地化支持,翻译
  • Flask-Login:认证用户状态
  • Flask-OpenID:认证
  • Flask-RESTful:开发REST API的工具
  • Flask-BOotstrap:集成前端Twitter Boostrap框架
  • Flask-Moment:本地化日期和时间
  • Flask-Admin:简单而可扩展的管理接口的框架

二、工程搭建

1、安装Flask

$ pip install flask

2、Hello World

# 导入Flask类 这个类的一个实例将是WSGI应用程序
from flask import Flask# 创建Flask类实例 第一个参数是应用程序的欧克或包的名称 __name__是适用于大多数情况的方便快捷方式 一边Flask知道在哪里寻找资源
app = Flask(__name__)@app.route('/')
def hello_world():return '<p>Hello, World!</p>'if __name__ == '__main__':app.run()

Bash

$ export FLASK_APP=hello
$ flask run -h 127.0.0.1 -p 5000* Running on http://127.0.0.1:5000/

CMD

> set FLASK_APP=hello
> flask run* Running on http://127.0.0.1:5000/
  • -h:绑定地址
  • -p:绑定端口

3、Flask对象初始化参数

Flask程序实例在创建的时候,需要默认传入当前Flask程序所指定的包(模块),以下是Flask应用程序在创建的时候一些需要我们关注的参数。

  • import_name
    • Flask程序所在的包(模块),传__name__即可。
    • import_name可以决定Flask在访问静态文件时查找的路径。
  • static_url_path
    • 静态文件访问路径,可以不穿值,默认为None
  • static_folder
    • 静态文件存储的文件夹,可以不传值,默认为static
  • template_folder
    • 模板文件存储的文件夹,可以不传值,默认为templates

4、应用程序配置参数

使用方式

Django将所有配置信息都放到了settings.py文件中,而Flask则不同。

Flask将配置信息保存到了app.config属性中,给属性可以按照字典类型进行操作。

读取

  • app.config.get(name)
  • app.config[name]

设置

主要使用以下三种方式:

  • 从配置对象中加载

    app.config.from_object(配置对象)

    class DefaultConfig(object):"""默认配置"""SECRET_KEY= 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'# 从配置对象中加载
    app.config.from_object(DefaultConfig)@app.route('/')
    def index():print(app.config['SECRET_KEY'])

    应用场景:

    ​ 作为默认配置写在程序代码中,可以继承

    class DevelopmentConfig(DefaultConfig):DEBUG=True
    

    优点:

    • 继承,可以复用

    缺点:

    • 敏感数据暴露在代码中
  • 从配置文件中加载

    app.config.from_pyfile(配置文件)

    新建一个配置文件setting.py

    SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    

    Flask程序文件中

    app = Flask(__name__)app.config.from_pyfile('setting.py')@app.route('/')
    def index():print(app.config['SECRET_KEY'])return 'hello world'
    

    应用场景:

    ​ 在项目中使用固定的配置文件

    优点:

    • 独立文件,保护敏感数据

    缺点:

    • 不能继承
    • 不灵活,文件路径
  • 从环境变量中加载

    环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。

    通俗的理解,环境变量就是我们设置在操作系统中,由操作系统代为保存的变量值

    在Linux系统中设置和读取环境变量的方式如下:

    # 设置变量 变量名=变量值
    export variable_name=variable_value# 读取变量
    echo $variable_name
    

    Flask使用环境变量加载配置的本质是通过环境变量值找到配置文件,再读取配置文件的信息,其使用方式为

    app.config.from_envvar('环境变量名')
    

    环境变量名的值为配置文件的绝对路径

    export PROJECT_SETTING='setting.py'
    

    Flash程序中

    app = Flask(__name__)app.config.from_envvar('PROJECT_SETTING', silent=True)
    

    silent表示系统环境变量中没有设置相应值时是否抛出异常

    • Flase:不安静处理,没有相应值时报错通知,默认为False。
    • Ture:安静处理,即使没有相应值也让Flask正常运行。

    优点:

    • 独立文件,保护敏感数据
    • 灵活,文件路径不固定

    缺点:

    • 不方便,要配置环境变量

工程模式

使用工厂模式创建Flask应用,并结合使用配置对象与环境变量加载配置

  • 使用配置对象加载默认配置
  • 使用环境变量加载不想出现在代码中的明杆信息
from flask import Flaskdef create_flask_app(config):"""创建Flask应用:param config: 配置对象:return: Flask应用"""# 创建Flask应用实例app = Flask(__name__)app.config.from_object(config)# 从环境变量指向的配置文件中读取的配置信息会覆盖掉从配置对象中加载的同名参数app.config.from_envvar('PROJECT_SETTING', silent=False)return appclass DefaultConfig(object):"""默认配置"""SECRET_KEY = 'X_X_X_X_X_X_X'class DevelopmentConfig(DefaultConfig):"""开发配置"""DEBUG = Trueapp = create_flask_app(DevelopmentConfig)@app.route('/')
def index():print(app.config['SECRET_KEY'])return 'hello world'if __name__ == '__main__':# 运行Flask提供的调试服务器app.run()

app.run 参数

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

app.run(host='0.0.0.0', port=5000, debug=True)

关于DEBUG调试模式

  1. 程序代码修改后可以自动重启服务器
  2. 在服务器出现相关错误的时候可以直接将错误返回到前端进行展示。

开发模式 & 生产模式

  • 开发环境(development):写程序的时候使用的环境。

    开发环境可以使用调试器(网页可以看到错误的详细信息)和重载器(代码修改自动重载)

  • 生产环境(production):程序上线以后使用的环境(默认为生产环境)。

# 开发模式
export FLASK_ENV=development# 生产模式
export FLASK_ENV=production

三、路由和蓝图

1、路由

查询路由信息

  • 命令行方式

    $ export FLASK_APP=hello
    $ flask routesEndpoint     Methods  Rule
    -----------  -------  -----------------------
    hello_world  GET      /
    static       GET      /static/<path:filename>
    
  • 程序中获取

    在应用程序中的url_map属性中保存着整个Flask应用的路由映射信息,可以通过读取这个属性获取路由信息。

    print(app.url_map)Map([<Rule '/' (HEAD, OPTIONS, GET) -> hello_world>, <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
    

    如果想在程序中遍历路由信息,可以采用如下方式:

    print([(rule.endpoint, rule.rule) for rule in app.url_map.iter_rules()])[('hello_world', '/'), ('static', '/static/<path:filename>')]
    

指定请求方式

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

  • HEAD(自带):简化版的GET请求,只返回GET请求处理时的响应头,不返回响应体。
  • OPTIONS(自带):简化版的GET请求,用于询问服务器接口信息。比如接口允许的请求方式,允许的请求源头域名。
  • GET

利用methods参数可以指定接口的请求方式。

@app.route('/case1/', methods=['POST'])
def hello_world():return '<p>Hello, World!</p>'@app.route('/case2/', methods=['GET', 'POST'])
def hello_world():return '<p>Hello, World!</p>'

2、蓝图

在Flask中,使用蓝图blueprint来分模块组织管理。

蓝图实际可以理解为是一个存储一组视图方法的容器对象,其具有如下特点:

  • 一个应用可以具有多个blueprint
  • 可以将一个blueprint注册到任何一个未使用的URL下,比如:/use//goods/
  • blueprint可以单独具有自己的模板、静态文件或者其他的通用操作方法,它并不是必须要实现应用的视图和函数。
  • 在一个应用初始化时,就应该要注册需要使用的blueprint

buleprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中。

单文件使用方式

  1. 创建一个蓝图对象

    # 创建蓝图对象
    use_bp = Blueprint('use', __name__)
    
  2. 在蓝图对象上进行操作,注册路由,指定静态文件夹,注册模板过滤器

    # 定义视图
    @use_bp.route('/')
    def index():return 'hello blueprint'
    
  3. 在应用对象上注册这个蓝图对象

    # 注册蓝图
    app.register_blueprint(use_bp)
    

目录蓝图

类似django的app应用

  1. 建立一个Python包,起名为goods,在该包的 __init__.py文件中定义蓝图。

    from flask import Blueprint# 定义蓝图
    goods_bp = Blueprint('goods', __name__)# 必须在定义蓝图后导入此文件否则项目无法找到视图 避免循环引用
    from . import views
    
  2. goods包中建立views.py,在views.py定义视图。

    from . import goods_bp@goods_bp.route('/goods/')
    def get_goods():return 'get_goods'
  3. 在应用对象中注册蓝图

    from goods import goods_bpapp.register_blueprint(goods_bp, url_prefix='/goods')
    

蓝图内部静态文件

​ 和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在创建是指定static_folder参数。

​ 下面的示例将蓝图所在目录下的static_admin目录设置为静态目录,之后可以使用/goods/static_goods/<filename>,可以通过static_url_path修改访问路径。

goods_bp = Blueprint('goods', __name__, static_folder='static_goods')

蓝图内部模板目录

​ 蓝图对象默认的模板目录为系统的模板目录,可以在创建蓝图对象时使用template_folder关键字参数设置模板目录。

goods_bp = Blueprint('goods', __name__, template_folder='template_goods')

四、请求与响应

1、处理请求

URL路径参数(动态路由)

例如,有一个请求访问的接口地址为/users/123,其中123实际上为具体的请求参数,表面请求123号用户的信息,此时如何从URL中提取出123的数据?

Flask不同于Django直接在定义路由时编写正则表达式的方式,而是采用转换器语法:

@app.route('/user/<user_id>')
def user_info(user_id):"""获取用户信息:param user_id: :return: """return f'hello {user_id}'

此处的<>是一个转换器,默认为字符串类型,将该位置的数据以字符串格式进行匹配、并以字符串为数据类型,user_id作为参数名传入视图。

Flask转换器

类型解释
string接受任何不带斜杠的字符
int接受正整数
float接受正浮点值
path接受字符但也接受斜杠
uuid接受UUID字符串

正整数

@app.route('/user/<int(min=10, max=100):user_id>')
def user_info(user_id):"""获取用户信息:param user_id::return:"""return f'hello {user_id}'	

自定义Flask转换器

  1. 创建转化器类,创建匹配时的正则表达式。

    from werkzeug.routing import BaseConverterclass MobileConverter(BaseConverter):"""手机号码转换器"""regex = r'1[1-9]\d{9}'
    

    注意:regex名字固定

  2. 将自定义的转换器告知Flask应用

    app = Flask(__name__)# 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为 mobile
    app.url_map.converters['mobile'] = MobileConverter
    
  3. 在使用转化器的地方定义使用。

@app.route('/sms_codes/<mobile:mob_num>')
def sms_codes(mob_num):"""获取用户信息:param mob_num::return:"""return f'{mob_num}'

其他参数

如果想要获取其他地方传递的参数,可以通过Flask提供的request对象来读取。不同的位置的参数都存放在request的不同属性中。

属性说明类型
data记录请求的数据,并转化为字符串*
form记录请求中的表单数据MultiDict
args记录请求中的查询参数MultiDict
cookies记录请求中的cookie信息Dict
headers记录请求中的报文头EnvironHeaders
method记录请求使用的HTTP方法GET/POST
url记录请求的URL地址string
files记录请求上传的文件*

args请求中的查询参数

http://127.0.0.1:5000/user?user_id=123

from flask import request@app.route('/user')
def user_info():"""获取用户信息:return:"""user_id = request.args.get('user_id')

上传图片

客户端上传图片到服务器,并保存到服务器。

from flask import request@app.route('/upload_file', methods=['POST'])
def upload_file():"""上传文件:return:"""# 接收文件file = request.files['picture']# 保存文件file.save('./demo.png')# 文件的参数名print(file.name)# 原来的文件名print(file.filename)return 'upload file success!'

2、处理响应

返回模板

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

Flask

from flask import render_template@app.route('/')
def index_template():"""模板渲染:return:"""data = {'name': 'Jack','age': 20,}return render_template('index.html', data=data)

jinja2

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>响应DEMO</title>
</head>
<body>
<h1>响应DEMO</h1>
<h1>{{ data['name']}}</h1>
<h1>{{ data['age']}}</h1>
</body>
</html>

重定向

from flask import redirect@app.route('/redirect')
def index_redirect():"""重定向:return:"""return redirect('https://wujing.blog.csdn.net/')

返回JSON

from flask import jsonify@app.route('/json')
def index_json():"""返回JSON数据:return:"""data = {'name': 'Jack','age': 20,}return jsonify(data)

jsonify

  • 将数据转化为json格式字符串
  • 设置响应头Content-Type:application/json

自定义状态码和响应头

  1. 元组方式

    可以返回一个元组,这样的元组必须是(response, status, headers)的形式,并且至少包含一个元素。

    status值会覆盖状态码,headers可以是一个列表或字典,作为额外的消息标头值。

    from flask import jsonify@app.route('/demo')
    def demo():"""自定义状态码和响应头:return: response, status, headers"""# return jsonify({'自定义状态码': 123}), 666, [('token', 123)]return jsonify({'自定义状态码': 123}), 666, {'token': 123}
  2. make_response方式

    from flask import make_response@app.route('/demo2')
    def demo2():"""make_response方式自定义状态码和响应头:return:"""resp = make_response('make_response方式自定义状态码和响应头')resp.headers['token'] = '123'resp.status = '404 not found'return resp
    

3、Cookie与Session

Cookie

  1. 设置cookie

    from flask import make_response
    from flask import jsonify@app.route('/set_cookie')
    def set_cookie():"""设置cookie:return:"""# 创建响应响应resp = make_response(jsonify({'设置cookie': '成功'}))# 设置cookieresp.set_cookie('username', 'jack', max_age=60)return resp
    
  2. 获取cookie

    from flask import request@app.route('/get_cookie')
    def get_cookie():"""获取cookie:return:"""# 从cookies中获取用户名username = request.cookies.get('username')return username
    
  3. 删除cookie

    from flask import make_response
    from flask import jsonify@app.route('/delete_cookie')
    def delete_cookie():"""删除cookie:return:"""# 创建响应resp = make_response(jsonify({'删除cookie': '成功!'}))# 删除cookieresp.delete_cookie('username')return resp
    

Session

需要先设置SECRET_KEY

from flask import Flaskapp = Flask(__name__)# 设置加密盐
app.secret_key = 'a_a_a_a_a_a_a_a'
  1. 设置session

    from flask import session@app.route('/set_session')
    def set_session():"""设置session:return:"""session['username'] = 'Jack'return '设置session成功!'
    
  2. 获取session

    from flask import session@app.route('/get_session')
    def get_session():"""获取session:return:"""name = session['username']return f'{name} 获取session成功!'
    
  3. 删除session

    from flask import session@app.route('/delete_session')
    def delete_session():"""删除session:return:"""session.pop('username', None)return '删除session成功!'
    

思考

flask将session数据保存到哪里了?

Flask中的session叫做浏览器session,保存在客户端的缓存中,通过设置secret_key添加签名来保证加密性。

五、请求钩子与上下文

1、异常处理

HTTP异常主动抛出

abort()抛出一个给定状态代码的HTTPException或者指定响应,例如想要用一个页面未找到异常来终止请求。

abort()抛出状态码智能是HTTP协议的错误状态码。

from flask import abort@app.route('/')
def index():"""异常抛出:return:"""c_id = request.args.get('c_id')# 如果没有传入参数c_id 抛出错误400if not c_id:abort(400)return c_id

捕获错误

errorhandler装饰器,注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法。

例如:同一给处理状态码为400的错误,给用户友好的提示。

@app.errorhandler(400)
def request_error(e):"""捕获请求错误400:param e::return:"""return '请求错误!'

例如:捕获指定异常

@app.route('/')
def index():"""异常抛出:return:"""raise TypeErrorreturn 'ok'@app.errorhandler(TypeError)
def request_error(e):"""捕获指定异常:param e::return:"""return '捕获了TypeError异常'

2、请求钩子

Django中间件,中间件的请求流程:

# 注册中间件
middlware_1,
middlware_2,
middlware_3,# 请求流程
middlware_1.process_request() -> middlware_2.process_request() -> middlware_3.process_request() -> view() -> middlware_3.after_request() -> middlware_2.after_request() -> middlware_1.after_request()# 中间件处理不区分具体是哪个视图,对所有视图统统生效。

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

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

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

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

  • before_first_request(f)

    注册一个在第一次请求此应用程序实例之前运行的函数。该函数将在没有任何参数的情况下被调用,并且其返回值将被忽略。

  • before_request(f)

    在每个请求之前注册一个要运行的函数。

    例如,这可用于打开数据库连接,或从会话加载登录用户。

    @app.before_request
    def load_user():if "user_id" in session:g.user = db.session.get(session["user_id"])
  • after_request(f)

    注册一个函数以在每次请求此对象后运行。

    该函数是用响应对象调用的,并且必须返回一个响应对象。这允许函数在发送之前修改或替换响应。

    如果函数引发异常,after_request则不会调用任何剩余的 函数。因此,这不应用于必须执行的操作,例如关闭资源。teardown_request()为此使用。

  • teardown_request(f)

    在每个请求结束时运行的函数,不管是否有异常。这些函数在请求上下文弹出时执行,即使没有执行实际请求。

from flask import Flask# 创建Flask实例
app = Flask(__name__)@app.route('/')
def index():"""请求钩子示例:return:"""print('view')return '请求钩子示例'@app.before_first_request
def before_first_request():print('before_first_request')@app.before_request
def before_request():print('before_request')@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')if __name__ == '__main__':app.run()

3、上下文(Context)

上下文实现原理:Threadlocal 线程局部变量。

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

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

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

请求上下文(request context)

思考:在视图函数中,如果取到当前请求的相关数据?比如:请求地址、请求方式、cookie等等、

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

  • request

    封装了HTTP请求的内容,针对的是HTTP请求。例如:user = request.args.get('user'),获取的是GET请求的参数。

  • session

    用来记录请求会话中的信息,针对的是用户信息。例如: session['name'] = user.id,可以记录用户信息,还可以通过session.get('name')获取用户信息。

上下文的作用

​ Flask里面内部实现的时候,虽然操纵的(request, session)是全局变量,可最终在不同的线程中使用的时候,却反应的线程内部的特征和整体没有关系,这样支持并发处理没有任何问题。

应用上下文(application context)

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

应用上下文对象有: current_appg

current_app

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

  • 应用的启动脚本是哪个文件,启动时指定了哪些参数。
  • 加载了哪些配置文件,导入了哪些配置。
  • 连接了哪些数据库。
  • 有哪些公共的工具类、常量。
  • 应用跑在哪个机器上,机器的IP地址,机器的内存。

示例

主程序

from flask import Flask
from blueprint_demo import bp# 创建Flask应用示例
app = Flask(__name__)# 模拟redis连接
app.redis_cli = 'redis连接'# 注册蓝图
app.register_blueprint(bp)@app.route('/')
def index():"""示例:return:"""return '请求成功!'if __name__ == '__main__':app.run()

蓝图

from flask import Blueprint
from flask import current_appbp = Blueprint('bp', __name__)@bp.route('/bp')
def bp_view():"""蓝图中定义视图:return:"""print(current_app.redis_cli)return 'bp'

current_app功能示例:current_app就是当前运行的Flask app,在代码不方便直接操作Flask的app对象时,可以操作current_app就等价与操作Flask App对象。

from flask import Flask
from flask import current_app# 创建Flask应用实例
app_1 = Flask(__name__)
app_2 = Flask(__name__)# 模拟redis连接
app_1.redis_cli = 'redis连接 1'
app_2.redis_cli = 'redis连接 2'@app_1.route('/demo_1')
def demo_1():return current_app.redis_cli@app_2.route('/demo_2')
def demo_2():return current_app.redis_cli
g对象

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

示例

from flask import Flask
from flask import g# 创建Flask应用实例
app = Flask(__name__)def db_query():"""数据库查询数据:return:"""user_id = g.user_iduser_name = g.user_name# 查询profileg.profile = str(user_id) + user_name@app.route('/')
def get_user_profile():g.user_id = 123g.user_name = 'jack'db_query()return g.profileif __name__ == '__main__':app.run()

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

需求

  • 构建认证机制
  • 对于特定视图可以提供强制要求用户登录的限制 ->装饰器
  • 对于所有视图,无论是否强制要求用户登录,都可以在视图中尝试获取用户认证后的身份信息 -> 钩子

实现

请求-> 请求钩子(尝试判断用户的身份 对于未登录用户方向) 用g对象保存用户身份信息 g.user_id = 123、g.user_id = None

->普通视图

->强势登录视图->装饰器

from flask import Flask
from flask import abort
from flask import g
from flask import render_template
from flask import jsonify# 创建Flask应用实例
app = Flask(__name__)@app.before_request
def authentication():"""用户认证利用before_request请求钩子在进入所有试图前先尝试判断用户身份:return:"""# TODO 此处利用鉴权机制(cookie、session、jwt等)鉴别用户身份信息# if# g.user_id = 123# elseg.user_id = Nonedef login_required(func):"""强制登录装饰器:param func::return:"""def wrapper(*args, **kwargs):if g.user_id is None:# 未登录abort(401)else:# 已登录return func(*args, **kwargs)return wrapper@app.route('/')
def index():"""首页不要求用户登录:return:"""return f'首页 {g.user_id}'@app.route('/profile')
@login_required
def get_user_profile():"""获取用户信息要求必须登录:return:"""return f'用户信息页面 {g.user_id}'@app.errorhandler(401)
def request_error(e):"""捕获指定异常:param e::return:"""# return render_template('login.html')return jsonify({'code': 401, 'data': '', 'msg': '未登录'})if __name__ == '__main__':app.run()

app_context与request_context

思考

​ 在Flask程序未运行的情况下,调试代码时需要使用current_appgrequest这些对象,会不会有问题?该如何使用?

app_context

app_context为我们提供了应用上下文环境,允许我们在外部使用应用上下文current_appg、可以通过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)
...
request_context

request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文requestsession可以通过with语句进行使用。

>>> from flask import request
>>> 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)
...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/7069.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24 ==比较的是地址在.equals比较的是内容

public class Demo1 {public static void main(String[] args) {byte[] arr {97,98,99};String s1 new String(arr);String s2 new String(arr);System.out.println(s1s2);System.out.println(s1.equals(s2));} }

Ubuntu16.04LTS安装ROS测试小海龟样例

一、参考资料 在Ubuntu中安装ROS Kinetic ROS安装ubuntu16.04 无需科学上网解决sudo rosdep init初始化问题 二、安装ROS关键步骤 1. 选择ROS版本 ROS安装选择 Ubuntu版本不同&#xff0c;对应安装的ROS版本也不同&#xff0c;务必版本对齐。 本文以Ubuntu16.04LTS系统为例…

MonoBehaviour 组件

MonoBehaviour 组件是指继承了 MonoBehaviour 类的脚本组件&#xff0c;可以附加到游戏对象上&#xff0c;用于控制游戏对象的行为和交互。 MonoBehaviour 类是 Unity 中的一个基类&#xff0c;提供了许多方法和事件&#xff0c;用于处理输入、渲染、碰撞、协程等操作。 Unity…

C盘空间不足:解决办法完整教程

当C盘空间不足时&#xff0c;你可以尝试以下几种解决方案&#xff1a; 1. 清理临时文件&#xff1a;使用Windows自带的磁盘清理工具&#xff0c;可以删除临时文件、回收站中的文件和其他不必要的系统文件&#xff0c;释放一些空间&#xff0c;推荐使用工具分区助手。 2. 卸载不…

React 框架下自己写一个braft编辑器,然后将编辑器内容展示在网页端

1.首先自己写一个编辑器 输入文字&#xff1b; 支持选择表情&#xff1b; 可添加小程序链接&#xff1b;可添加网页链接&#xff1b;并且可以编辑删除&#xff1b;效果如下 2.输入完毕后&#xff0c;点击文本输入框保存&#xff0c;将便携式内容回显&#xff0c; 渲染时…

[MySQL]MySQL用户管理

[MySQL]MySQL用户管理 文章目录 [MySQL]MySQL用户管理1. 用户的概念2. 用户信息3. 创建用户4. 修改用户密码5. 删除用户6. MySQL中的权限7. 给用户授权8. 回收权限 1. 用户的概念 MySQL中的用户分为超级用户&#xff08;root&#xff09;和普通用户。超级用户的操作是不受权限…

机器人制作开源方案 | 智能垃圾桶

1. 功能说明 智能垃圾桶是一种利用物联网技术和智能感知能力的智能设备&#xff0c;旨在提高垃圾分类和处理的效率。通常具备以下特点和功能&#xff1a; ① 智能感知&#xff1a;智能垃圾桶配备各种传感器&#xff0c;如压力传感器、红外线传感器等&#xff0c;可以实时感知…

Spring Cloud 之 Gateway 网关

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

网络安全 Day20-计算机网络基础知识05(网络原理)

计算机网络基础知识05&#xff08;网络原理&#xff09; 1. OSI 模型2. VMware虚拟机NAT模式下上网原理3. 不能上网故障排查 1. OSI 模型 OSI 7层网络通信原理模型 OSI 国际网互联 OSI 数据包封装解封装过程 北京局域网主机A到深圳局域网主机B数据工作流程 2. VMware虚拟机N…

VUE中的生命周期、每个生命周期可以干什么

生命周期 就VUE来说就是一个程序的即将创建到销毁的一个过程&#xff0c;也就是vm对象实例从创建到最终销毁的过程。 VUE生命周期4个阶段8个钩子函数(到某一阶段自动调用的函数) 1.初始阶段&#xff08;虚拟的DOM生成&#xff09; beforeCreate() 初始化事件对象和生命周期…

人类机器人编程的心理机制(一)

\qquad 本文中的人类机器人编程(Human Robot Programming)意指“基于创伤的脑控(trauma-based mind control, T.B.M.C)”或“基于创伤的编程(trauma-based programming)”&#xff0c;文中用英文缩写“T.B.M.C”指代。T.B.M.C的操纵主体是施加编程的个人或机构&#xff0c;文中…

el-table 表头设置渐变色

<el-table :data"tableData" stripe><el-table-column prop"name" label"测试" align"left"></el-table-column><el-table-column prop"code" label"测试1" align"left"></…

Sui Move与标准Move的有哪些区别和根本性创新

Sui网络将Sui Move作为其本地编程语言&#xff0c;使用Sui Move编写的apps利用Sui的共识机制&#xff0c;实现了令人印象深刻的交易性能。 然而&#xff0c;熟悉Move编程语言的开发者在探索Sui文档时可能会感到困惑&#xff0c;因为该文档着重介绍了对象和一些指令&#xff0c…

kafka消费者api和分区分配和offset消费

kafka消费者 消费者的消费方式为主动从broker拉取消息&#xff0c;由于消费者的消费速度不同&#xff0c;由broker决定消息发送速度难以适应所有消费者的能力 拉取数据的问题在于&#xff0c;消费者可能会获得空数据 消费者组工作流程 Consumer Group&#xff08;CG&#x…

git 提示 不能合并

今天A分支合并B分支&#xff0c;提示“不能合并” 最终发现&#xff0c;是另一个分支的版本落后导致&#xff0c;但是git并未提示出来 有遇到这种问题可以先检查下版本

如何有效跟踪你的计费时间?

对于自由职业者、小型企业和远程团队来说&#xff0c;时间跟踪是必需的。了解自己在单个项目或任务上投入了多少时间&#xff0c;可以帮助他们有效管理资源和优化工作流程。 然而&#xff0c;在向客户收费时&#xff0c;时间跟踪多了一层复杂性&#xff1a;不仅需要跟踪所花费…

Linux工具——vim

安装vim yum -y install vim 如果安装失败&#xff0c;提示Could not resolve host:mirrorlist.centos.org: Unkown error的问题&#xff0c;需要替换yum源&#xff0c;可以参考这个文章 配置vim root的vim配置文件在 /etc/vimrc 普通用户的vim配置文件在用户对应家目录下&a…

react实现页面动态表单设计器(自定义推拽表单)

react实现页面动态表单设计器&#xff08;自定义推拽表单&#xff09; 实现效果安装插件使用组件介绍基本设置&#xff0c;可设置控件标签&#xff0c;是否必填&#xff0c;校验规则校验规则有如下几种多选&#xff0c;下拉&#xff0c;单选可动态设置每个选择的label以及值 实…

一百三十三、Hive——Hive外部表加载含有JSON格式字段的CSV文件数据

一、目标 在Hive的ODS层建外部表&#xff0c;然后加载HDFS中的CSV文件数据 注意&#xff1a;CSV文件中含有未解析的JSON格式的字段数据&#xff0c;并且JSON字段中还有逗号 二、第一次建外部表&#xff0c;直接以&#xff0c;分隔行字段&#xff0c;结果JSON数据只显示一部分…

【1++的C++初阶】之list

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;什么是list二&#xff0c;构造与析构2.1 结点结构2.2 链表结构2.3 迭代器结构 三&#xff0c;部分重要接口的作用及其实现3.1 迭代器相关的接口3.2 list相关…