Flask教程2:flask高级视图

文章目录

        • 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:指定视图函数的名称

from flask import Flask,url_for

app = 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')) # 输出结果为/test

if __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文件如下:

from flask import Flask,render_template,views

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

from flask import Flask

app = 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(<形参名>)即可;

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对象,并为拓展模块中的蓝图对象提供注册入口
from flask import Flask
from file import news,products

app = 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
from flask import Blueprint

# 实例化蓝图对象,参数一类似于蓝图对象的名称
# 一个app下的蓝图对象不可重名
new_list = Blueprint('news',__name__)

# 蓝图对象的使用和app类似
# 一个蓝图下的视图函数名、endpoint不可重复
@new_list.route('/news')
def new():
    return '这是新闻模块!'
  • 模块二:products.py
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":

new_list = Blueprint('news',__name__,url_prefix='/index')

@new_list.route('/news')
def new():
    return '这是新闻模块!'

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter笔记:Widgets Easier组件库(1)使用各式边框

Flutter笔记 Widgets Easier组件库&#xff08;1&#xff09;&#xff1a;使用边框 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

【stomp 实战】Spring websocket 用户订阅和会话的管理源码分析

通过Spring websocket 用户校验和业务会话绑定我们学会了如何将业务会话绑定到spring websocket会话上。通过这一节&#xff0c;我们来分析一下会话和订阅的实现 用户会话的数据结构 SessionInfo 用户会话 用户会话定义如下&#xff1a; private static final class Sessio…

利用Argo数据分别计算温度、盐度和温盐所造成的比容海平面变化

本文所用到的温盐数据集&#xff1a;IPRC&#xff08;美国夏威夷大学国际太平洋研究中心&#xff09; Argo data products | Argo (ucsd.edu)https://argo.ucsd.edu/data/argo-data-products/ 理论知识&#xff08;相关计算公式&#xff09;&#xff1a; 代码和工具包准备&…

python 中的数据结构

python 中的数据结构 1.1 序列 序列时有索引的数组 举例实现&#xff1a; a["北京","上海","广州","深圳","重庆","成都"] print(a[2]) print(a[-1] " " a[-2]) print(a[1:3]) # 运行结果 "&…

Vulnhub-DIGITALWORLD.LOCAL: VENGEANCE渗透

文章目录 前言1、靶机ip配置2、渗透目标3、渗透概括 开始实战一、信息获取二、smb下载线索三、制作字典四、爆破压缩包密码五、线索分析六、提权&#xff01;&#xff01;&#xff01; Vulnhub靶机&#xff1a;DIGITALWORLD.LOCAL: VENGEANCE ( digitalworld.local: VENGEANCE …

chrome和drive安装包路径

Chrome for Testing availability (googlechromelabs.github.io) 下载Stable下面的包哈

【Leetcode每日一题】 分治 - 排序数组(难度⭐⭐)(69)

1. 题目解析 题目链接&#xff1a;912. 排序数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 归并排序&#xff08;Merge Sort&#xff09;是一种采用“分而治之”&#xff08;Divide and Conquer&#xff09;策略…

LLM之RAG实战(三十八)| RAG分块策略之语义分块

在RAG应用中&#xff0c;分块是非常重要的一个环节&#xff0c;常见的分块方法有如下几种&#xff1a; Fixed size chunkingRecursive ChunkingDocument Specific ChunkingSemantic Chunking a&#xff09;Fixed size chunking&#xff1a;这是最常见、最直接的分块方法。我们…

C/C++基础语法练习 - 计算阶乘(新手推荐阅读✨)

题目链接&#xff1a;https://www.starrycoding.com/problem/160 题目描述 给定一个整数 n n n&#xff0c;输出阶乘 n ! n! n!。 输入格式 一个整数 n ( 1 ≤ n ≤ 20 ) n(1 \le n \le 20) n(1≤n≤20)。 输出格式 一个整数 n ! n! n!。 输入样例1 16输出样例1 20922…

树的中心 树形dp

#include<bits/stdc.h> using namespace std; int n; const int N 100005; // 无向边 int ne[N * 2], e[N * 2], idx; int h[N]; int vis[N];int ans 0x7fffffff;void add(int a, int b) {e[idx] b, ne[idx] h[a], h[a] idx; }int dfs(int u) { // 作为根节点vis[u]…

机器学习:基于Sklearn,使用随机森林分类器RandomForestClassifier检测信用卡欺诈

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

分享一份物联网 SAAS 平台架构设计

一、架构图**** 二、Nginx**** 用于做服务的反向代理。 三、网关**** PaaS平台所有服务统一入口&#xff0c;包含token鉴权功能。 四、开放平台**** 对第三方平台开放的服务入口。 五、MQTT**** MQTT用于设备消息通信、内部服务消息通信。 六、Netty**** Socket通信设…

IoTDB 入门教程①——时序数据库为什么选IoTDB ?

文章目录 一、前文二、性能排行第一三、完全开源四、数据文件TsFile五、乱序数据高写入六、其他七、参考 一、前文 IoTDB入门教程——导读 关注博主的同学都知道&#xff0c;博主在物联网领域深耕多年。 时序数据库&#xff0c;博主已经用过很多&#xff0c;从最早的InfluxDB&a…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-9.1-LED灯(模仿STM32驱动开发实验)

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

IDEA:Server‘s certificate is not trusted(服务器的证书不受信任)

IDEA&#xff1a;Server‘s certificate is not trusted&#xff08;服务器的证书不受信任&#xff09; 打开idea&#xff0c;发现一个莫名其妙的证书弹出来&#xff0c;还关不掉发现组织名是 Doctorcom LTD.百度了下 不知道是什么东西 这也不是下面这种破解了idea的情况 30069…

Ajax.

目录 1. 服务器相关的基础概念 1.1 服务器 1.2 客户端 1.3 服务器对外提供的资源 1.4 数据也是资源 1.5 资源与 URL 地址 1.6 什么是 Ajax 2. Ajax 的基础用法 2.1 POST 请求 2.2 GET 请求 2.3 DELETE 请求 2.4 PUT 请求 2.5 PATCH 请求 3. axios 3.1 axios 的基…

IoTDB 入门教程 问题篇①——内存不足导致datanode服务无法启动

文章目录 一、前文二、问题三、分析四、继续分析五、解决问题 一、前文 IoTDB入门教程——导读 二、问题 执行启动命令&#xff0c;但是datanode服务却无法启动&#xff0c;查询不到6667端口 bash sbin/start-standalone.sh 进而导致数据库连接也同样失败 [rootiZ2ze30dygwd6…

Go 语言(三)【面向对象编程】

1、OOP 首先&#xff0c;Go 语言并不是面向对象的语言&#xff0c;只是可以通过一些方法来模拟面向对象。 1.1、封装 Go 语言是通过结构体&#xff08;struct&#xff09;来实现封装的。 1.2、继承 继承主要由下面这三种方式实现&#xff1a; 1.2.1、嵌套匿名字段 //Add…

实操——使用uploadify插件(php版和Java版) 与 Dropzone.js插件分别实现附件上传

实操——使用uploadify插件&#xff08;php版和Java版&#xff09;与 Dropzone.js插件分别实现附件上传 1. 使用uploadify插件上传1.1 简介1.1.1 简介1.1.2 参考GitHub 1.2 后端PHP版本的uploadify1.2.1 下载项目的目录结构1.2.2 测试看界面效果1.2.3 附页面代码 和 PHP代码 1.…

ctfshow——SQL注入

文章目录 SQL注入基本流程普通SQL注入布尔盲注时间盲注报错注入——extractvalue()报错注入——updataxml()Sqlmap的用法 web 171——正常联合查询web 172——查看源代码、联合查询web 173——查看源代码、联合查询web 174——布尔盲注web 176web 177——过滤空格web 178——过…