深入学习Flask框架之视图及路由
Posted fangtaoa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入学习Flask框架之视图及路由相关的知识,希望对你有一定的参考价值。
在前面一讲中我们学习如何创建一个简单的Flask项目,并做了一些简单的分析。接下来在这一节中就主要来讲讲Flask中最核心的内容之一:Werkzeug工具箱。Werkzeug是一个遵循WSGI协议的Python函数库。WSGI协议在前面的文章中也有提到(点我查看)。那Werkzeug有什么作用呢?它其实实现了很多底层的东西,如Request、Response和集成URL请求路由等。
一、Werkzeug的组成:
二、routing模块
routing模块的主要目的是负责实现URL解析。不同的URL能够对应不同的视图,从而得到不同的响应信息。
1.Rule类:class Rule(RuleFactory):
用来构造不同的url模式的对象。
1 if not string.startswith(‘/‘):
2 raise ValueError(‘urls must start with a leading slash‘)
这个判断语句是Rule中的,表示url必须是以"/"开头的字符串!
2.Map类:
用来存储所有的URL规则和一些配置参数。
3.MapAdapter类
负责让url与视图建立关联。
4.BaseConverter
这是一个转换器基类,Flask中6个自带的转换器都是继承于它!当然了,如果我们想要自定义一个路由匹配规则的话,也需要通过继承它来实现。如自定义一个正则路由匹配。
流程:
(1). 导入BaseConverter类。在Flask中,所有 的路由的匹配规则都是使用转换器对象进行记录的。
(2). 自定义转换器。
(3). 把自定义转换器添加到默认转换器的字典当中去。
(4). 使用自定义转换器实现自定义匹配规则。
from flask import Flask
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class RegexConverter(BaseConverter):
"""自定义一个正则转换器"""
def __init__(self, map, *args):
super(RegexConverter, self).__init__(map)
# 将url中第一个参数当做匹配规则进行保存
self.regex = args[0]
print(map)
print(args[0])
# 把自定义转换器添加到默认转换器的字典中,并将转换器命名为re
app.url_map.converters[‘re‘] = RegexConverter
# print(app.url_map.converters)
# 定义一个正则的路由规则,匹配3个数字
@app.route(‘/regex/<re("[0-9]{3}"):u_id>‘)
def index(u_id):
return "user_id为%s" % u_id
if __name__ == "__main__":
print(app.url_map)
app.run(debug=True)
三、Request对象
Request是Flask中表示当前请求的request对象,一般称之为请求上下文变量(可以理解成全局变量,在任意一个视图中都可以访问到)。常用的属性有:
args:url中的查询字符串。本质上是键值对,跟在"?"后面,多个键值对之间使用"&"连接;
form:请求url中的表单数据。也是由键值对组成,一般使用post方法提交数据
cookies:请求中的cookie信息。由服务器生成的键值对,把值发送给客户端并保存,稍后重点讲解!
files:上传的文件
1 from flask import Flask, request
2
3
4 app = Flask(__name__)
5
6
7 # 127.0.0.1:5000/?a=4&b=5
8 @app.route(‘/‘)
9 def index():
10 a = request.args.get(‘a‘)
11 b = request.args.get(‘b‘)
12
13 print(‘a:%s, b:%s‘ % (a, b))
14 return ‘请求成功!!‘
15
16
17 if __name__ == "__main__":
18 print(app.url_map)
19 app.run(debug=True)
四、状态保持
在分析Request对象的时候提到过Cookie,什么是Cookie?Cookie有什么用?以及如何通过Cookie及Session来实现状态保持呢?
(1). 为什么要有状态保持的功能?
因为HTTP是一种无状态协议,也就是说当用户每一次请求时,都是一个新的请求,服务器根本不知道这个用户做过什么。比如当你在某个网站上想要买个东西,但是你每做一步都需要进行登录直到下单成功,这样对用户来说就显得特别麻烦,用户体验就特别差。如果我们的网站可以记录该用户的一些信息,那么用户就不需要每次都进行登录了,用户体验就大大提高了。
(2).Cookie是什么?
Cookie是由键值对组成的字符串,为了辨别用户身份,进行会话跟踪而保存在本地的数据。
Cookie是服务器生成的,发送给客户端浏览器,浏览器将以键值对的形式保存着,当下一次请求同一网站的时候会携带着Cookie一起。
有了Cookie我们就可以在很多地方看到一些似曾相识的广告了!比如当你在某宝上买了什么玩意,然后系统会推荐很多很多的相似的东西好让你剁手!
Cookie是基于域名安全的,不同域名的Cookie是不能相互访问的。这就牵扯到CSRF了,这个留在模板中来说。
1 from flask import Flask, request, make_response
2
3 app = Flask(__name__)
4
5
6 @app.route(‘/set_cookie‘)
7 def set_cookie():
8 # make_response()用来生成一些响应头信息
9 # 参数作为响应体
10 resp_header = make_response(‘用来生成响应头信息‘)
11 # 设置cookie,key为unmae, value为python, 有效期为1分钟
12 resp_header.set_cookie(‘uname‘, ‘python‘, max_age=60)
13 return resp_header
14
15
16 @app.route(‘/get_cookie‘)
17 def get_cookie():
18 name = request.cookies.get(‘uname‘,"没有获取到有效的cookie")
19 return name
20
21
22 if __name__ == "__main__":
23 print(app.url_map)
24 app.run(debug=True)
(3). session是什么?
在做Cookie的实验中,我们发现Cookie保存的信息是明文形式,这样是很不安全的。而且又是保存在本地的,不是保存在服务器上面。这样的话,我们一些很重要的私人信息是会很容易被盗取。那有没有一种保存在服务器的秘钥,而且又是被加密的,返回给浏览器的只是一个key呢?
那么session就是这样的,保存在服务器,而且是加密的,不容易被盗取。但是Session是依赖于Cookie的。
session在Flask中是一种请求上下文对象,用于处理HTTP请求中的一些数据。
如果要设置Session,那么必须要设置SECRET_KEY变量。SECRET_KEY 的作用主要是提供一个值做各种 HASH,可在 Flask 和多个第三方扩展中使用。
在上面提到过,一些配置信息最好不要和业务逻辑混合在一起。要么单独存放在一个文件中,如settings.py,要么存放在一个ini文件中,或者添加到系统环境变量里。这么做的好处是如果你不把这些文件暴露出去,那么其他人就很难看到!在Flask中都有提供这些操作接口(app.config.from_xxx()),很方便
1 from flask import Flask, session
2
3 # 自定义的配置文件,为了安全起见,里面可以做一些数据库连接、秘钥设置...
4 from settings import MyConfig
5
6 app = Flask(__name__)
7
8 # 从.py的配置文件中加载一些配置变量,如DEBUG, SECRET_KEY,...
9 app.config.from_object(MyConfig)
10
11
12 @app.route(‘/session‘)
13 def set_session():
14 session[‘name‘] = ‘python‘
15 return ‘设置session成功‘
16
17
18 if __name__ == "__main__":
19 print(app.url_map)
20 app.run()
五、请求钩子
在Flask中有一个请求钩子,就是4个装饰器。但是在其他框架中,如Django、Scrapy中被称为中间件,所以也可以把请求钩子称作是中间件!这其实是一种编程思想(AOP切面编程)的体现。对AOP编程感兴趣的读者可以自行搜索了解一下!这里主要讲讲Flask中的请求钩子。
Flask中的请求钩子分别是:before_first_request、before_request、after_request、teardown_request。这些请求钩子有什么作用呢?可以把他们想象成C++/Java中的构造函数和析构函数,即做一些初始化和销毁的工作!其中最主要的功能还是在请求结束时,指定数据的交互格式,如指定Json格式。
[email protected]_first_request:在处理第一个请求前被执行,而且只会执行一次。
[email protected]_request:每次请求前被执行,可以做一些预检工作,如果不满足某些条件就return,然后视图就不会被执行了
[email protected]_request:在每个视图执行完毕之后并且没有错误时调用,可以设置一些响应头信息,等等操作。必须返回response
[email protected]_request:每次请求后被调用,接受一个参数:错误信息。
1 from flask import Flask, request, abort
2
3 from settings import MyConfig
4
5 app = Flask(__name__)
6
7 # 配置信息
8 app.config.from_object(MyConfig)
9
10
11 # 第一次请求前被调用,相当于__init__方法
12 @app.before_first_request
13 def before_first_request():
14 print(‘我只会被调用一次哦!‘)
15
16
17 # 在每次请求前被调用,可以做一些请求检验
18 # 如果请求的检验不成功,可以直接在此方法中进行响应,直接return后,不在继续往下执行
19 @app.before_request
20 def before_request():
21 print(request.args.get(‘wd‘, ‘没有找到查询参数‘))
22 if "?" not in request.url:
23 # 这个return 语句返回个客户端浏览器,并作为响应体
24 return ‘url中没有查询参数‘
25 print(‘你的请求URL:%s‘ % request.url)
26 # abort(500)
27
28
29 # 执行完视图函数之后被调用,并且会把视图函数生成的响应传入,可以对response做一些设置
30 #
31 @app.after_request
32 def after_request(response):
33 # print(response.headers)
34
35 # if response.headers.startswith(‘text‘):
36 # response.headers[‘Content-Type‘] = ‘application/json‘
37 print(‘对响应信息做了一些更改!‘)
38 # 必须返回一个response
39 return response
40
41
42 # 在每次请求之后都会被调用,会接受一个参数,参数是服务器出现的错误信息
43 @app.teardown_request
44 def teardown_request(e):
45 print(‘teardown_request‘)
46 print(e)
47
48
49 @app.route(‘/args/<int:p1>‘)
50 def index1(p1):
51 return "接收到参数%s" % p1
52
53
54 @app.route(‘/args/<int:p2>‘)
55 def index2(p2):
56 return "接收到参数%s" % p2
57
58
59 if __name__ == ‘__main__‘:
60 app.run()
以上是关于深入学习Flask框架之视图及路由的主要内容,如果未能解决你的问题,请参考以下文章