Flask教程2:flask高级视图

server/2024/12/22 14:48:31/

文章目录

        • add_url_rule
        • 类视图的引入
        • 装饰器的自定义与使用
        • 蓝图的使用
        • url_prefix设置蓝图前缀

add_url_rule

欲实现url与视图函数的绑定,除了使用路由装饰器@app.route,我们还可以通过add_url_rule(rule,endpoint=None,view_func=None)方法,其中:

rule:设置的url
endpoint:给url设置的名称
view_func:指定视图函数的名称

python">from flask import Flask,url_forapp = Flask(__name__)@app.route('/',endpoint='index')
# 底层其实是使用add_url_rule实现的
def hello_world():return 'Hello World!'def my_test():return '这是测试页面'
app.add_url_rule(rule='/test',endpoint='test',view_func=my_test)# 请求上下文只有在发送request请求时才会被激活,激活后request对象被设置为全局可访问
# 其内部封装了客户端发出的请求数据报文
# 此处是主动生成一个临时的测试请求上下文
with app.test_request_context():print(url_for('test')) # 输出结果为/testif __name__ == '__main__':app.run(debug=True)

在这里插入图片描述

类视图的引入

之前我们所定义的视图都是通过函数来实现的,所以称之为视图函数,但其实视图还可以由类来实现,即类视图;

  • 标准类视图:
  • 定义时需要继承flaskviews.View这一基类;
  • 每个类视图内必须包含一个dispatch_request方法,每当类视图接收到请求时都会执行该方法,返回值的设定和视图函数相同;
  • 视图函数可以通过@app.routeapp.add_url_rule来进行注册(映射到url),但类视图只能通过app.add_url_rule来注册,注册时view_func不能直接使用类名,需要调用基类中的as_view方法来为自己取一个“视图函数名”

采用类视图的最大优势,就是可以把多个视图内相同的东西放在父类中,然后子类去继承父类;而类视图不方便的地方,就是每一个子类都要通过一个add_url_rule来进行注册。
下面将创建一个网站包含三个页面,每个页面中都展示相同的对联广告,py文件如下:

python">from flask import Flask,render_template,viewsapp = Flask(__name__)# 定义父视图类继承基类View
class Ads(views.View):def __init__(self):super(Ads, self).__init__()# 实例属性self.context={'ads':'这是对联广告!'}# 定义子视图类继承父类并实现工程
class Index(Ads):def dispatch_request(self):# 字典传参方式==不定长的关键字传参return render_template('class_mould/index.html',**self.context)
class Login(Ads):def dispatch_request(self):# 字典传参方式==不定长的关键字传参return render_template('class_mould/login.html',**self.context)
class Register(Ads):def dispatch_request(self):# 字典传参方式==不定长的关键字传参return render_template('class_mould/register.html',**self.context)# 注册我们创建的类视图,as_view给类视图起名
app.add_url_rule(rule='/',endpoint='index',view_func=Index.as_view('index'))
app.add_url_rule(rule='/login/',endpoint='login',view_func=Login.as_view('login'))
app.add_url_rule(rule='/register/',endpoint='register',view_func=Register.as_view('register'))if __name__=='__main__':print(app.view_functions)app.run(debug=True)
python">WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on http://127.0.0.1:5000
Press CTRL+C to quit* Restarting with watchdog (windowsapi)
{'static': <function Flask.__init__.<locals>.<lambda> at 0x000001E8685FFBE0>, 'index': <function View.as_view.<locals>.view at 0x000001E868644C10>, 'login': <function View.as_view.<locals>.view at 0x000001E8686453F0>, 'register': <function View.as_view.<locals>.view at 0x000001E868645480>}* Debugger is active!* Debugger PIN: 109-993-459

在这里插入图片描述

  • 基于方法的类视图:
    当我们需要根据不同请求来实现不同逻辑时,用视图函数需要在内部对请求方法做判断,但我们使用方法类视图就可以通过重写其内部方法简单实现;
    Flask除了基本类视图,还为我们提供了另一种类视图flask.views.MethodView,在其内部编写的函数方法即是http方法的同名小写映射
装饰器的自定义与使用

装饰器本质上是一个python函数,他可以让其他函数在不需要做任何代码变得的前提下增加额外的功能,其传入参数一般是函数对象(如视图函数),返回值也是一个函数对象;
装饰器主要用于有切面需求的场景,如插入日志、性能测试、事务处理等与函数功能无关的操作,对于这些需要多次重用的代码,我们将其放置在装饰器里,就可以无需在每个函数中反复编写;

python">from flask import Flaskapp = Flask(__name__)@app.route('/')
def hello_world():return 'Hello World!'# 定义装饰器函数
def user_login(func):def inner():# 替代登录操作print('登录操作!')# 执行传入的函数对象func()# 此处如果return inner(),那么返回的是inner函数的执行结果# 而使用return inner,则返回的是inner函数return inner# 定义新闻页面视图函数news
def news():print('这是新闻详情页!')
# 将news函数作为参数传给装饰器函数
show_news=user_login(news)
# 因为user_login返回inner函数,所以show_news()==inner()
show_news()
# 打印出show_news的真实函数名(为inner)
print(show_news.__name__)if __name__ == '__main__':app.run(debug=True)

上述代码的运行逻辑是这样的:首先我们将新闻页面函数作为一个参数传给装饰器,装饰器将我们需要插入的登录操作与我们的视图函数包装成一个inner函数对象并返回,最后执行该对象便可以实现在新闻页面显示前执行登录操作;

刚才我们展示的是不含参数的函数使用装饰器,对于带参数的函数我们同样也可以使用装饰器,这里要先回顾Python的可变参数:

def func(*args,**kwargs) :

*:代表元组,长度不限;
**:代表键值对,个数不限;
*args:指用元组传参,元组内包含不定个数的位置参数;
**kwargs:指用字典传参,字典内包含不定个数的关键字参数(键值对);

可以使用functools.wraps方法来保留原函数的属性与名称,通俗一点理解就是“不换外包装”;
方法的导入:from functools import wraps;
在自定义的装饰器下方添加一行@wraps(<形参名>)即可;

python">from functools import wraps# 定义装饰器函数
def user_login(func):@wraps(func)# inner函数接收参数def inner(*args,**kwargs):print('登录操作!')# 执行传入函数时使用inner接收到的参数func(*args,**kwargs)return inner
蓝图的使用

上述类视图、装饰器分别通过继承、包装的方式减少了单个flask程序文件里重复代码的出现,实现了程序的优化;

但是这样处理后的文件内,不同功能的代码块(类视图、视图函数)仍然混杂在一起。如果要制作一个非常大型的程序项目,这样不仅会让代码阅读变得十分困难,而且不利于后期维护;

为了解决这一问题,我们需要引入蓝图(flask.Blueprint),用于实现程序功能的模块化;
导入方法:from flask import Blueprint

当接收到请求时,Flask会遍历Flask对象下(已注册)的各蓝图对象,比对蓝图对象中记录的url,比对成功则映射到该url绑定的视图函数并返回响应

  • 主路由视图函数:创建flask对象,并为拓展模块中的蓝图对象提供注册入口
python">from flask import Flask
from file import news,productsapp = Flask(__name__)
@app.route('/')
def hello_world():return 'hello my world !'# 将对应模块下的蓝图对象注册到app中
app.register_blueprint(news.new_list)
app.register_blueprint(products.product_list)if __name__ == '__main__':app.run(debug=True)
  • Blueprint对象的工作方式与Flask对象类似,但其不是一个单独的应用; 每拓展一个蓝图对象,就要在主路由文件下添加一行注册代码;
  • 蓝图对象内记录了当前模块下的所有视图函数,固视图函数不可与蓝图对象同名;
  • 在蓝图内需要通过蓝图对象来定义路由和调用其他装饰器,由蓝图对象定义的路由处于休眠状态,在蓝图被注册时才成为程序的一部分。
  • 模块一:news.py
python">from flask import Blueprint# 实例化蓝图对象,参数一类似于蓝图对象的名称
# 一个app下的蓝图对象不可重名
new_list = Blueprint('news',__name__)# 蓝图对象的使用和app类似
# 一个蓝图下的视图函数名、endpoint不可重复
@new_list.route('/news')
def new():return '这是新闻模块!'
  • 模块二:products.py
python">from flask import Blueprint# 实例化蓝图对象,参数一类似于蓝图对象的名称
# 一个app下的蓝图对象不可重名
product_list = Blueprint('products',__name__)# 蓝图对象的使用和app类似
# 一个蓝图下的视图函数名、endpoint不可重复
@product_list.route('/products')
def product():return '这是产品模块!'

如此一来,我们便将不同功能的视图函数定义在了不同的模块下,实现了程序的工程化。

在这里插入图片描述

url_prefix设置蓝图前缀

一般在蓝图对象定义时添加,为当前蓝图下的所有视图函数添加统一的前缀,这样不同蓝图下的视图函数的url就不易发生重复;

如下例添加前缀后,加载该新闻模块的url就变为"/index/news":

python">new_list = Blueprint('news',__name__,url_prefix='/index')@new_list.route('/news')
def new():return '这是新闻模块!'

在这里插入图片描述
如下例中,注册后的新闻模块的url又变为了"/test/news":

python">app.register_blueprint(news.new_list,url_prefix='/test')

在这里插入图片描述


http://www.ppmy.cn/server/26205.html

相关文章

如何判断嵌入式平台OpenCV在使用硬件编解码器?

01 涉及OpenCV编解码库的一个命令行工具 python3 -c import cv2; print(cv2.getBuildInformation()) 它可以打印输出详细的OpenCV编译参数和当前的媒体库相关参数&#xff0c;我的rk3588打印的信息是这样的&#xff1a; catlubancat:~$ python3 -c import cv2; print(cv2.getBu…

面试准备之九种排序算法之快速排序

快排的时间复杂度为nlog(n) 实现方式如下&#xff1a; 首先定义一个交换函数swap&#xff0c;一个取两个下标中间下标并返回的函数findpivot。一个主函数用于划分数组&#xff0c;进行实际快排的函数&#xff0c;一个执行数组排序操作的函数。他们之间的关系是主函数首先判断…

Adobe PS 2023、Adobe Photoshop 2023下载教程、安装教程

Adobe Photoshop &#xff08;<-下载连接&#xff09;简介&#xff1a; Adobe Photoshop是一款广泛使用的图像处理软件&#xff0c;由Adobe公司开发。它提供了许多强大的工具和功能&#xff0c;可以用于图像编辑、合成、修饰、设计等各个领域。用户可以使用Photoshop来调整…

Fastadmin 日常项目常见用法整理

ps&#xff1a;自己使用笔记备用&#xff0c;不间断更新&#xff0c;常见功能点 一&#xff0c;数据库后缀 结尾字符示例类型要求字段说明timerefreshtimebigint/datetime识别为日期时间型数据&#xff0c;自动创建选择时间的组件imagesmallimagevarchar识别为图片文件&#…

大模型公开课-大模型的语言解码游戏学习总结

在当今快速发展的人工智能领域&#xff0c;深度学习作为其中的一项关键技术&#xff0c;正引领着科技的新潮流。而对于初学者来说&#xff0c;了解大型语言模型的解码游戏&#xff0c;对于理解深度学习的基本概念至关重要。本篇博客将对一次关于大型语言模型解码游戏的视频教学…

人形机器人狂潮来袭

奔跑、咖啡拉花、搬箱子、叠衣、分拣物品、吸尘清洁……曾存在于科幻电影中的人形机器人&#xff0c;正加速走进人类社会。 去年以来&#xff0c;伴随着AI大模型浪潮&#xff0c;被视为AI最佳载体的人形机器人似乎驶入了一条快车道&#xff0c;科技巨头纷纷入局&#xff0c;产…

小程序云开发(十六):小程序API实战

&#x1f517; 运行环境&#xff1a;小程序云开发 &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 &#x1f510;#### 防伪水印——左手の明天 ####&#x1f510; &#x1f497…

将SSH密钥添加到GitHub账户

1、生成SSH密钥对&#xff1a; 首先&#xff0c;您需要在本地计算机上生成一个新的SSH密钥对。打开终端或命令提示符&#xff0c;然后运行以下命令。请确保替换your_emailexample.com为您GitHub账户关联的电子邮件地址。这里我们使用Ed25519算法&#xff0c;因为它既安全又高效…