上一节完成第一个入门程序hello world后,这一节学习flask中url的知识。
URL中是可以添加变量部分的,即将同一种规则的url抽象成一种模式,比如/aaa/1、/aaa/2、/aaa/3...如果不抽象路径,就需要写上n次:
@app.route('/aaa/1')
@app.route('/aaa/2')
@app.route('/aaa/3')
...
def aaa():
return 'aaa执行'
所以,如果有一种方式可以把数字部分全部抽象成一个变量,不就方便多了吗?写法如下:
@app.route('/aaa/')
def aaa(id):
return 'aaa-id:{}'.format(id)
也就是说将路径中的某一部分作为变量传入视图函数中,在这里将
细心的朋友可以看到,这样接收的变量是没有指定类型的,其实这里默认为字符串类型,指定类型以及自带的类型如下:
- string:接受任何无斜杠"/"的文本,这是默认的类型
- ing:接受整数
- float:接受浮点数
- path:与string类似但是接受斜杠
- uuid:只接受uuid字符串,多用于图片的访问
- any:可以指定多种路径,但需要传参
@app.route('/aaa/
/') 那么访问/aaa/a/和/aaa/b/都会符合这个路径,/aaa/a/的variable_name就是a
如果自带的转换器(就是上面说的类型指定)不能满足需求,还可以自定义转换器,
假如现有需求为:通过访问localhost:5000/demo1/flask+django就能同时看django和flask的帖子,那么自带的转换器就无法解决。
自定义URL转换器,实现对上述url的转换。
from flask import Flask
from werkzeug.routing import BaseConverter
from urllib import parse as urlparse
app = Flask(__name__)
class MyConverter(BaseConverter):
def __init__(self, url_map, sep='+'):
super(MyConverter, self).__init__(url_map)
self.sep = urlparse.unquote(sep)
def to_python(self, value):
return value.split(self.sep)
def to_url(self, values):
return self.sep.join(BaseConverter.to_url(value=value) for value in values)
app.url_map.converters['list'] = MyConverter
@app.route('/demo1//')
def demo1(page_names):
return "page_names={" + ','.join(page_names) + '}'
if __name__ == '__main__':
app.run(debug=True)
然后运行并访问:
需要注意自定义转换器继承者BaseConverter,要设置to_python和to_url两个方法。
- to_python:将路径转换为python对象
- to_url:将python对象转换为url形式
http有多种访问方法,默认的情况下,app.route装饰器只响应GET请求,向app.route装饰器中传递methods参数可以修改响应的类型。
@app.route('/aaa',methods=['GET','POST'])
@app.route('/bbb/',methods=['DELETE','POST'])
以下为http方法和常用场景:
GET:获取资源
HEAD:获取资源但是只关心消息头,不返回实际内容。
POST:创建新的资源,是表单最常用的请求类型
PUT:替换资源或者创建资源
DELETE:删除资源
OPTIONS:获取资源支持的所有HTTP方法
PATCH:局部更新,修改某个资源
在国内很多只用了GET和POST两种方法,偏离REST的风格。
用url_for构建URL,它接受函数名作为第一个参数,也接受对于URL规则的变量部分的命名参数,未知变量部分会添加到URL末尾作为查询参数,使用url_for构建URL的原因:
- 在以后有更改时,只需一次修改URL,而不用到处替换
- 构建URL会转义特殊字符和Unicode数据
以下代码:
...引入相关函数等...
app = Flask(__name__)
@app.route('/demo3_1/')
def demo3(id):
return "demo3:{" + id + '}'
@app.route('/demo3_2/')
def demo3_2(a):
return url_for('demo3', a=a, id=100, s='多余参数')
if __name__ == '__main__':
app.run(debug=True)
当访问/demo3_2/2/时:
即,url_for返回第一个参数(函数名)对应的url,这里就是/demo3_1/
显然接受变量id为路径,而变量a和s则作为查询参数和/demo3_1/id拼接,
最终得到上图结果。
url_for只是将第一个参数对应url和参入的参数进行拼接,并不会执行第一个参数对应的函数。
跳转(状态码301):将对旧网址的访问转向新网址,有页面永久性转移的概念。
重定向(状态码302): 表示页面是暂时性的转移。
@app.route('/demo4')
def demo4():
name = request.args.get('name')
if not name:
return redirect(url_for('demo4_2'))
user_agent = request.headers.get('User-Agent')
return 'name:{0},User-Agent:{1}'.format(name, user_agent)
@app.route('/demo4_2',methods=['GET','POST'])
def demo4_2():
if request.method == 'POST':
user_id = request.form.get('user_id')
return 'User-ID:{}'.format(user_id)
else:
return 'login page'
@app.route('/demo4_3')
def demo4_3():
abort(401)
return 'never executed'
1. 访问demo4的请求会被301跳转到/demo4/上。
2. request.headers 存放请求头的信息
3. request.method 为请求类型
4. abort(401)将放弃请求,禁止访问,其后的代码永远不会执行
5. redirect为重定向,根据传入的url进行重定向,通常配合url_for
web开发中少不了处理404请求的情况,在flask中以下两种方式都能对404请求进行处理,其中第二种方式更加灵活,可以去设置cookie,头信息等。
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'),404
@app.errorhandler(404)
def not_found(error):
rsp = make_response(render_template('error.html'),404)
return rsp