(十三)Flask之特殊装饰器详解

目录:

  • Flask中用作装饰器的特殊的函数
    • 第一部分:`before_request`和`after_request`
      • 一、 `before_request`装饰器:
      • 二、`after_request`装饰器:
      • 三、多个`before_request`和`after_request`执行流程分析:
        • 首先—理论讲解:
        • 然后—实战讲解:
        • 最后—扒扒源码:
        • 画图形象记忆:
    • 第二部分:实战—使用`before_request`进行身份验证
    • 第三部分:补充常见特殊装饰器
      • 一、`@app.errorhandler(code)`:
      • 二、 `@app.teardown_request`:
      • 三、`@app.template_test`:
      • 四、`@app.before_first_request`:

Flask中用作装饰器的特殊的函数

第一部分:before_requestafter_request

在Flask中,before_requestafter_request是用作装饰器的特殊函数,它们可以用来在请求处理过程中执行某些操作。

一、 before_request装饰器:

  • 通过在函数上使用@app.before_request装饰器,可以将该函数注册为全局的请求前钩子(hook)。这意味着每次请求到达服务器时,在实际处理请求之前,都会先执行被before_request装饰的函数。
  • before_request函数通常用于执行一些预处理任务,例如验证用户身份、设置全局变量、打开数据库连接等。它可以修改请求或应用程序上下文,并且可以返回响应对象或 None(后面扒扒源码看看)。

比如:

@app.before_request
def before_request():# 执行一些预处理任务if not current_user.is_authenticated:return redirect(url_for('login'))

二、after_request装饰器:

  • 通过在函数上使用@app.after_request装饰器,可以将该函数注册为全局的请求后钩子。这意味着在每次请求完成并返回响应之后,都会执行被after_request装饰的函数。

  • after_request函数通常用于执行一些后处理任务,例如**添加响应头、记录请求日志、关闭数据库连接等。**它接收一个参数,即响应对象,并且必须返回一个响应对象。

比如:

@app.after_request
def after_request(response):# 执行一些后处理任务response.headers['X-Frame-Options'] = 'SAMEORIGIN'return response

通过使用before_requestafter_request装饰器,可以在请求的前后执行一些共同的逻辑,从而实现全局的预处理和后处理操作。这样可以避免在每个视图函数中重复编写相同的代码。

三、多个before_requestafter_request执行流程分析:

首先—理论讲解:

当存在多个before_requestafter_request装饰器时,分析它们的执行顺序:

  1. before_request执行流程:

    • 当一个请求到达服务器时,首先会执行第一个注册before_request装饰的函数。
    • 如果该函数返回了一个响应对象,则停止执行后续所有的before_request函数,而是直接返回该响应对象给客户端。
    • 如果该函数没有返回响应对象,则继续执行下一个注册的before_request函数,以此类推,直到所有的before_request函数都被执行完毕。
  2. after_request执行流程:

    • 在每次请求完成并返回响应之后,从最后一个注册after_request装饰的函数开始执行。
    • 每个after_request函数都会接收前一个after_request函数所返回的响应对象作为参数,并且必须返回一个新的响应对象。
    • 执行完最后一个after_request函数后,最终的响应对象将会发送给客户端。
然后—实战讲解:
from flask import Flask, sessionapp = Flask(__name__)  # 创建Flask应用程序对象@app.before_request
def before_request_1():print("Before Request 1")@app.before_request
def before_request_2():print("Before Request 2")@app.after_request
def after_request_1(response):print("After Request 1")return response@app.after_request
def after_request_2(response):print("After Request 2")return response@app.route('/')
def index():print("Index Page")return "Hello, World!"if __name__ == '__main__':app.run()

输出的执行顺序如下:

在这里插入图片描述

可以看到,首先执行了before_request_1before_request_2两个函数,然后处理了请求并返回响应,接着按照相反的顺序执行了after_request_2after_request_1两个函数。

最后—扒扒源码:

为何before_request是按注册顺序执行,而after_request是按注册倒序执行嘞?

扒一扒源码就晓得啦~

直接进入before_requestafter_request的身体:

在这里插入图片描述

上面就是Flask注册before_requestafter_request函数的方法,一模一样!

下面来扒下Flask执行before_requestafter_request函数部分的源码:

进入app.__call__()后直到full_dispatch_request函数:

在这里插入图片描述

在这里插入图片描述

关注点先放在上图第二个for循环,其余部分后续会慢慢探究~

before_request_funcs 就是上述包含了请求前钩子函数的字典。这些函数会在请求分发(即dispatch_request)之前被调用。

遍历每个注册的请求前钩子函数,并执行它们。如果任何一个请求前钩子函数**返回一个非 None 的值,该值会被当作视图函数的返回值处理(直接返回给客户端页面),并且后续的请求处理流程会被停止【但是after_request正常执行!】;**如果没有任何请求前钩子函数返回非 None 值,那么 preprocess_request 方法会返回 None。

来个代码讲解:

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

画图形象记忆:

绿色就是所有请求前钩子函数(before_request)返回值都为None时的执行流程;

相应的,白色就是有一个返回值非None时的执行流程。
在这里插入图片描述

差点忘了带大家看after_request了!

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

在这里插入图片描述

看到没!reversed!!!反向遍历哦~

第二部分:实战—使用before_request进行身份验证

上代码:

from flask import Flask, request, redirect, url_for, render_template, sessionapp = Flask(__name__)# 模拟的用户数据库
users = {'admin': {'username': 'admin','password': 'GuHanZhe'}
}@app.before_request
def authenticate_user():# 获取当前请求的路径path = request.path# 如果请求的路径不是登录页面,进行身份验证if path != '/login':# 检查 session 中是否存在已登录的用户if 'username' not in session:# 用户未登录,重定向到登录页面return redirect(url_for('login'))@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']# 在实际开发中,这里需要进行密码验证if username in users and users[username]['password'] == password:# 登录成功,将用户名保存在 session 中session['username'] = usernamereturn redirect(url_for('protected_page'))else:# 登录失败,显示错误信息error_message = "Invalid username or password."return render_template('login.html', error_message=error_message)return render_template('login.html')@app.route('/protected')
def protected_page():return "This is a protected page. Only logged-in users can access it."if __name__ == '__main__':app.run()

在上述代码中,before_request 钩子函数 authenticate_user 用于验证用户身份。它会在每个请求到达之前被调用,除了登录页面 /login 外的所有页面都需要进行身份验证。

如果用户未登录,authenticate_user 函数将重定向到登录页面,使用 redirect 函数和 url_for 函数实现页面重定向。登录成功后,将用户名保存在 session 中,以便在后续的请求中进行验证。

login 路由处理函数负责渲染登录页面,并接收用户提交的表单数据。在实际应用中,需要根据数据库中的用户信息进行密码验证。验证成功后,将用户名保存在 session 中,并重定向到受保护的页面 /protected

protected_page 路由处理函数是一个示例的受保护页面,只有登录用户可见。

第三部分:补充常见特殊装饰器

一、@app.errorhandler(code)

  • 这是用于注册错误处理函数的装饰器。
  • code 参数指定了需要处理的错误码,例如 404、500 等。
  • 装饰的函数将作为错误处理函数,在出现指定错误码时被调用,并返回自定义的错误页面或响应。

二、 @app.teardown_request

用于注册在每个请求结束时执行的函数。它可以用来进行一些清理操作或释放资源。

实战:

from flask import Flaskapp = Flask(__name__)@app.route('/')
def index():return "Hello, World!"@app.teardown_request
def teardown_request_func(error=None):print("Teardown function is called after each request.")if __name__ == '__main__':app.run()

在上述代码中,定义了一个名为 teardown_request_func 的函数,并使用 @app.teardown_request 装饰器将其注册为每个请求结束时执行的函数。

当我们访问任何路由时,Flask 会在请求结束后自动调用 teardown_request_func 函数。无论请求是否出现错误,该函数都会被执行。

需要注意的是,@app.teardown_request 装饰的函数只能接受一个参数,即可选的错误对象。如果要访问请求上下文中的其他对象,可以使用 flask.request 对象。

这个装饰器通常用于进行一些清理操作,例如关闭数据库连接、释放资源等。

三、@app.template_test

用于注册自定义模板测试函数的装饰器。

实战:

from flask import Flaskapp = Flask(__name__)@app.template_test('even')
def is_even(number):return number % 2 == 0if __name__ == '__main__':app.run()

通过 @app.template_test('even') 装饰器将 is_even 函数注册为一个名为 “even” 的模板测试函数。该函数用于判断一个数字是否是偶数。

在模板中,可以使用 {% if %} 语句来调用这个模板测试函数:

{% if num is even %}<p>The number is even</p>
{% else %}<p>The number is odd</p>
{% endif %}

通过注册模板测试函数,我们可以在模板中使用自定义的逻辑判断函数,以便根据特定的条件进行动态渲染和显示不同的内容。

四、@app.before_first_request

用于注册在第一个请求到达之前执行的函数。它只会在应用程序启动时执行一次。

实战:

from flask import Flaskapp = Flask(__name__)@app.before_first_request
def before_first_request_func():print("This function is executed before the first request.")@app.route('/')
def index():return "Hello, World!"if __name__ == '__main__':app.run()

在上述代码中,before_first_request_func 被装饰为 @app.before_first_request,它会在第一个请求到达之前执行。

当我们运行这个应用程序时,before_first_request_func 函数会在第一个请求到达之前执行一次。之后,每个请求到达时,都不会再次调用该函数。

需要注意的是,@app.before_first_request 装饰的函数仅在主线程中执行,并且只有在应用程序启动时才会被调用一次。如果使用多线程或多进程部署应用程序,可以考虑使用其他方法来进行初始化操作。

【新版本Flask没有这个装饰器了~】

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

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

相关文章

Python3 面向对象

面向对象技术简介 类&#xff08;Class&#xff09;&#xff1a;用来描述具有相同属性的方法和对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。方法&#xff1a;类中定义的函数类变量&#xff1a;类变量在整个实例化的对象中是公用的。类变量定义在…

微软Azure AI新增Phi、Jais等,40种新大模型

微软在官方宣布在Azure AI云开发平台中&#xff0c;新增了Falcon、Phi、Jais、Code Llama、CLIP、Whisper V3、Stable Diffusion等40个新模型&#xff0c;涵盖文本、图像、代码、语音等内容生成。 开发人员只需要通过API或SDK就能快速将模型集成在应用程序中&#xff0c;同时支…

Java EE 进程线程

JavaEE 进程&线程 文章目录 JavaEE 进程&线程1. 进程1.1 概念1.2 进程管理1.3 PCB (Process Control Block) 2. 线程2.1 概念2.1 线程与进程的区别2.3 创建线程 1. 进程 1.1 概念 什么是进程&#xff1f; 进程是操作系统对一个正在执行的程序的一种抽象 我们可以打开…

Python编程基础

Python是一种简单易学的编程语言&#xff0c;广泛应用于Web开发、数据分析、人工智能等领域。无论您是初学者还是有一定编程经验的人士&#xff0c;都可以从Python的基础知识开始建立自己的编程技能。 目录 理论Python语言的发展程序设计语言的分类静态语言与脚本语言的区别 代…

Allegro层叠中的介电常数如何填写指导说明

Allegro层叠中的介电常数如何填写指导说明 在用Allegro进行PCB设计的时候,需要在cross-section中设置好每个层的信息,包括层命名,每层的厚度等等信息。如下图 一般来说,这些信息就足够了 但是对于有仿真需求或者等长设计需要使用ps作为延时单位的设计的时候,需要额外在层…

JVM基础篇:垃圾回收

1.前言 1.1C/C的内存管理 在C/C这类没有自动垃圾回收机制的语言中&#xff0c;一个对象如果不再使用&#xff0c;需要手动释放&#xff0c;否则就会出现内存泄漏。我们称这种释放对象的过程为垃圾回收&#xff0c;而需要程序员编写代码进行回收的方式为手动回收。内存泄漏指的…

6.12找树左下角的值(LC513-M)

算法&#xff1a; 这道题适合用迭代法&#xff0c;层序遍历&#xff1a;按层遍历&#xff0c;每次把每层最左边的值保存、更新到result里面。 看看Java怎么实现层序遍历的&#xff08;用队列&#xff09;&#xff1a; /*** Definition for a binary tree node.* public clas…

C++——解锁string常用接口

本篇的内容是记录使用string接口的测试与使用&#xff0c;方便后续使用时查阅使用 首先介绍 string::npos; size_t&#xff08;无符号整型&#xff09;的最大值。NPOS 是一个静态成员常量值&#xff0c;具有 size_t 类型元素的最大可能值。当此值用作字符串成员函数中 len&am…

Linux多路转接select,poll

文章目录 目录 文章目录 一、五种IO模型 1.阻塞IO: 2.非阻塞IO 3.信号驱动IO 4.IO多路转接 5.异步IO 二、高级IO的一些重要概念 1.同步通信和异步通信 2.阻塞和非阻塞 三、其他高级IO 四、非阻塞IO 1.fctl函数 2.实现setNoBlock函数&#xff0c;将文件描述符设置…

好玩的调度技术-生成式三维技术

好玩的调度技术-生成式三维技术 文章目录 好玩的调度技术-生成式三维技术前言一、效果图&#xff1f;二、技术实现系列文章链接其他文章新篇章 前言 目前休息了&#xff0c;预计休息半年&#xff0c;这半年里只会零星更新一些好玩的技术&#xff0c;感觉好玩系列都快成系列文章…

详解如何使用VSCode搭建TypeScript环境(适合小白)

搭建Javascript环境 因为TypeScript不能直接在浏览器上运行。它需要编译器来编译并生成JavaScript文件。所以需要首先安装好javascript环境&#xff0c;可以参考文章&#xff1a; 详解如何使用VS code搭建JavaScript环境&#xff08;适合小白&#xff09;_vscode配置javascri…

LeetCode Hot100 437.路径总和III

题目&#xff1a; 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从…

不可错过的设计工具!7款亲测好用的网页设计工具推荐!

网页设计并不容易&#xff0c;易于使用的网页设计工具更难找到。随着网络的快速发展&#xff0c;网站迅速崛起&#xff0c;网页设计也很流行。本文收集了 7 种良心和易于使用的网页设计工具&#xff0c;每一种近年来都受到网页设计师的广泛欢迎&#xff0c;以确保实用和易于使用…

前端技术探秘-Nodejs的CommonJS规范实现原理 | 京东物流技术团队

了解Node.js Node.js是一个基于ChromeV8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模型&#xff0c;让JavaScript 运行在服务端的开发平台&#xff0c;它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。Node中增添了很…

免费商用字体,进来领取!!!

如果你不知道去哪里找免费可商用字体&#xff0c;那一定要收藏好这几个网站&#xff0c;全部都是免费无版权字体&#xff0c;以后再也不用担心侵权问题了。 1、免费字体网 https://font.sucai999.com/ 一个免费可商用字体搬运工&#xff0c;实时跟新市面上免费商用的字体。网站…

国家万亿资金助力城市生命线城市内涝积水监测系统

自2023年年初以来&#xff0c;我国多个地区遭遇了洪涝、干旱、台风、风雹等灾害的侵袭&#xff0c;部分地区灾情严重&#xff0c;经济损失较大。为应对灾后恢复重建工作的艰巨任务&#xff0c;本次国债将主要投向灾后恢复重建以及提升防灾减灾救灾能力。其中&#xff0c;将全面…

12V 全桥驱动芯片GC9008,0.1A 持续驱动输出电流,可替代MX6208

GC9008 是一款 12V 全桥驱动芯片&#xff0c;为 摄像机、消费类产品提供高性价比的方案。能提供 0.1A 的持续输出电流。 可以工作在 4.5~15V 的电源电压上。 GC9008 具有 PW &#xff08; IN1/IN2 &#xff09;输入接口 , 与行业标准器件兼容. GC9008S 是 SOP8 封装&a…

【JavaEE初阶】 博客系统项目--前端页面设计实现

文章目录 &#x1f332;主要内容&#x1f38d;预期效果&#x1f6a9;博客列表页效果&#x1f6a9;博客详情页&#x1f6a9;博客登录页&#x1f6a9;博客编辑页 &#x1f340;实现博客列表页&#x1f6a9;实现导航栏&#x1f388;页面主体部分 &#x1f384;实现博客详情页&…

【多线程】-- 04 静态代理模式

多线程 3 静态代理 这里以一个现实生活中的例子来解释并实现所谓的静态代理模式&#xff0c;即结婚者雇用婚庆公司来帮助自己完成整个婚礼过程&#xff1a; package com.duo.lambda;interface Marry {void HappyMarry();//人生四大乐事&#xff1a;久旱逢甘霖&#xff1b;他…