Flask视图和URL
Posted Flask学习笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask视图和URL相关的知识,希望对你有一定的参考价值。
URL
重定向和url_for
1.url_for
这个函数接受视图函数的名称(字符串的形式),返回视图函数对应的
URL
语法:
url_for(endpoint, **values)
endpoint
:节点,指代视图函数
values
:关键字参数,对应视图函数中的变量例子:
#!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask import url_for
# 初始化
app = Flask(__name__)
# 路由
@app.route('/')
def index():
return 'index page!'
@app.route('/login/<uname>/<upasswd>')
def login(uname,upasswd):
return 'welcome'
@app.route('/get/')
def get_url():
my_url = url_for("login", uname='Jack', upasswd='123')
return my_url
if __name__ == '__main__':
app.run(debug = True)返回的是一个标准的
url
路径。
2.redirct
重定向
跳转到指定的
URL
,和url_for()
一起使用return redirct(my_url)
浏览器由一个路径跳转到另外的路径,这就是重定向,典型的如用户登录页面的跳转。
永久性重定向:HTTP代码是301
暂时性重定向: HTTP代码是302.
例子:
#!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask import redirect,url_for
app = Flask(__name__)
@app.route('/login/')
def login():
info = """
<html>
<head>
</head>
<body>
<div>
<input type="button", value="name">
<input type="text", value="">
<input type="button", value="passwd">
<input type="text", value="">
<input type="button", value="submit">
</div>
</body>
</html>
"""
return info
@app.route('/')
def index():
Url = url_for('login')
return redirect(Url)
if __name__ == "__main__":
app.run(debug=True)
3.版本控制
$ git log
$ git status
$ git add .
$ git commit -m "add url_for,redirect.v1.005"
$ git status
4.在动态路由中自定义URL
转换器
现在我们已经知道了,在动态路由的时候,有很多的
converter
,比如int,float,string,path,uuid
等等。当然,也可以自定义一个转换器,只要满足相应的规则即可。
导入转换器继承类:
from werkzeug.routing import BaseConverter
自定义一个转换器,继承自
BaseConverter
类。映射到
URL
转换器的默认字典中:app.url_map.converter['key'] = value
使用自定义转换器
1.定制转换器只使用正则表达式
例子:
#!/usr/bin/env python
# conding = utf-8
from flask import Flask
# 导入继承类
from werkzeug.routing import BaseConverter
# 初始化
app = Flask(__name__)
# 自定义一个转换器
class TelphoneConverter(BaseConverter):
regex = r'1[3-9][0-9]{9}'
# 映射转换器字典
app.url_map.converters['tel'] = TelphoneConverter
# 使用自定义转换器
@app.route('/tel/<tel:tel_num>/')
def phoneNum(tel_num):
return 'welcome:{}'.format(tel_num)
if __name__ == '__main__':
app.run(debug = True)访问匹配到正则的号码可以看到界面,反之则不行
2.定制转换器复杂化
定制转换器中可以实现方法
to_python
和to_url
.
to-python
:强化正则表达式,进行额外的验证,将匹配到的字符串转换为其他对象.并且应该引发一个werkzeug.routing.ValidationError
错误,web会返回500
错误.
to_url
:在构建URL时将Python对象转换为字符串. 此处引发的任何错误都将转换为werkzeug.routing.BuildError
并最终导致500
错误解释例子:假设当前有一个购物网站,有2名会员登录,一个采购了2本书,另外一个采购了2件衣服,网站上还有很多的笔记本和台式机等物品。
#!/usr/bin/env python
# coding=utf-8
# 数据库
books_information = {
'python': 18,
'java': 19,
'c++': 20,
'c': 21
}
clothes_information = {
'red': 18,
'block': 19,
'yellow': 20
}
pcs_information = {
'hp': 18,
'dell': 19,
'alien': 20
}
vips_information = {
'18818808891',
'18818808899'
}
# 采购信息对应
from flask import Flask
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class Phone_Coverter(BaseConverter):
"""手机号的正则转换"""
regex = r'1(([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}'
# 注册到URL转换器中
app.url_map.converter['phone'] = Phone_Coverter
@app.route('/')
def index():
return "Shopping web"
@app.route('/<phone:my_phone>')
def handle_phone(my_phone):
if my_phone in vips_information:
return 'welcome VIP:{}'.format(my_phone)
else:
return 'please register'
# 会员购买信息
# 会员购买信息
@app.route('/18818808891/<book_name>/')
def books_detail(book_name):
if book_name == 'python':
return 'This book is {} and price is {}'.format(book_name, str(book_informathion[book_name]))
elif book_name == 'java':
return 'This book is {} and price is {}'.format(book_name, str(book_informathion[book_name]))
elif book_name == 'python+java':
book_name = book_name.split('+')
return 'The book is {} and {}'.format(book_name[0], book_name[1])
else:
return 'Not this book'
@app.route('/18818808899/<clothes_name>/')
def clothes_detail(clothes_name):
if clothes_name == 'red':
return 'The clothes color is {}, price is {}'.format(clothes_name, str(clothes_information[clothes_name]))
elif clothes_name == 'black':
return 'The clothes color is {}, price is {}'.format(clothes_name, str(clothes_information[clothes_name]))
elif clothes_name == 'red+black':
clothes_name = clothes_name.split('+')
return 'The clothes is {} and {}'.format(clothes_name[0], clothes_name[1])
else:
return 'Not this clothes'
@app.route('/get/18818808891/')
def get_books_detail():
info = url_for('books_detail', book_name='python+java')
return info
@app.route('/get/18818808899/')
def get_clothes_detail():
info = url_for('clothes_detail', clothes_name='red+black')
return info
if __name__=='__main__':
app.run(debug=True)但是这样有一个问题就是,假如会员3有新的2个物品比如pc机器,就需要从新写一下
split()
方法,如果有非常多的数据就会很不方便.python是面向对象语言,那么我们就可以把相同的抽离出去.
自定义继承的类
BaseConverter
默认提供了2个方法to_python
,to_url
就可以来处理上面的问题,我们只需要在自己写的类中重写这两个方法就可以.
# 自定义处理split
class Handle_List(BaseConverter):
"""自定义处理A+B"""
# regex =
def to_python(self, value):
"""转换url为其他对象"""
print(value)
return value.split('+')
def to_url(self, value):
"""转换其他对象为url"""
print(value)
if type(value) == str:
return value
else:
return '+'.join(value)
# 注册到默认URL转换器中
app.url_map.converters['hlist'] = Handle_List
最后写出来的效果是:
# 数据库,实物和价格的对应
books_information = {
'python': 18,
'java': 19,
'c++': 20,
'c': 21
}
clothes_information = {
'red': 18,
'black': 19,
'yellow': 20
}
pcs_information = {
'hp': 18,
'dell': 19,
'alien': 20
}
vips_information = {
'18818808891',
'18818808899'
}
# 实现每个会员自己的采购信息
from flask import Flask,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
@app.route('/')
def index():
return '购物网站'
# 自定义Phone类
class Phone_Coverter(BaseConverter):
"""手机号的正则表达式"""
regex = r'1(([3][0-9])|([4][5-9])|([5][0-3,5-9])|([6][5,6])|([7][0-8])|([8][0-9])|([9][1,8,9]))[0-9]{8}'
# 添加到默认URL转换器中
app.url_map.converters['phone'] = Phone_Coverter
# 自定义处理split
class Handle_List(BaseConverter):
"""自定义处理A+B"""
# regex =
def to_python(self, value):
"""转换url为其他对象"""
print(value)
return value.split('+')
def to_url(self, value):
"""转换其他对象为url"""
print(value)
if type(value) == str:
return value
else:
return '+'.join(value)
# 注册到默认URL转换器中
app.url_map.converters['hlist'] = Handle_List
@app.route('/<phone:my_phone>/')
def handle_phone(my_phone):
if my_phone in vips_information:
return 'welcome VIP:{}'.format(my_phone)
else:
return 'Please register'
# 会员购买信息
@app.route('/18818808891/<hlist:book_name>/')
def books_detail(book_name):
return 'The books is {}'.format(book_name)
@app.route('/18818808899/<hlist:clothes_name>/')
def clothes_detail(clothes_name):
return 'The clothes color is {}'.format(clothes_name)
@app.route('/get/18818808891/')
def get_books_detail():
info = url_for('books_detail', book_name='python+java')
return info
@app.route('/get/18818808899/')
def get_clothes_detail():
# 处理 to_url
info = url_for('clothes_detail', clothes_name=['red', 'black'])
return info
if __name__ == '__main__':
app.run(debug=True)访问
http://127.0.0.1:5000/18818808891/python+java/
The books is ['python', 'java']
访问
http://127.0.0.1:5000/18818808899/red+black/
The clothes color is ['red', 'black']
5.版本控制
$ git add .
$ git commit -m "add 定制转换器。v1.006"
6.视图函数Response
Response
:指响应,指的是客户端发送给服务器请求信息后(getpost
),服务器反馈给客户端的行为就是响应。比如,新建一个简单的站点,通过浏览器查看响应信息。
from flask import Flask, Response
# from werkzeug.wrappers import Response
app = Flask(__name__)
@app.route('/')
def index():
return 'The Response object'
@app.route('/response/')
def my_response():
return Response('The Response object')
if __name__ == '__main__':
app.run(debug=True)通过浏览器查看:
1.Flask
对Response
的置换逻辑
Response
其实来自于werkzeug
中的定义,导入的方式可以有2种from flask import Flask, Response
from werkzeug.wrappers import Response根据定义来看,在
Flask
中:
如果返回的是一个合法的
Response
对象,直接返回如果返回的是一个字符串,
Flask
会重新创建一个werkzeug.wrapper.Resonse()
对象.它会将字符串作为主体,状态码200
,MIME类型为text/html
返回.如果返回的是一个元组,元组的数据类型是
(Response, status, headers)
,status
会更新状态码,hearder
可以是一个列表或者字典,作为额外的消息头如果返回的是一个字典,
Flask
会自动返回一个json
字符串如果以上条件都不满足,
Flask
会假设返回值是一个合法的wsgi
应用可以自定义响应方法
force_type
2.自定义Response
自定义消息应该注意以下:
Response
子类: 自定义的类必须是Response
的子类
force_type
: 实现方法force_type(cls,response,envison=None)
==> 当返回的数据类型不是字符串和元组,Flask
会调用force_type
方法来处理,不能处理时就会报错,所以子类一般都会重写这个方法来处理自己的返回数据类型,从而返回返回合法的数据类型.参数response
就是传入的不合法数据.
response_class
: 使用app.response_class=MyResponse
生效from flask import Flask,Response,jsonify
app = Flask(__name__)
@app.route('/')
def index():
"""Flask 内部会转回字符串"""
return 'response object'
@app.route('/tuple/')
def my_tuple():
"""Flask 响应元组"""
return Response('tuple:response object', 200)
@app.route('/dict/')
def my_dict():
"""Flask 字典会返回一个jison字符串"""
user_information = {
'name':'python',
'price':'18'
}
return user_information
@app.route('/list/')
def my_list():
"""访问不支持的数据类型会报错"""
user_list = ['python', 'java']
return user_list
if __name__ == "__main__":
app.run(debug=True)当在浏览器中访问
http://127.0.0.1:5000/list/
时,会弹出报错信息TypeError
TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a list.现在通过自定义
Response
来处理list
:"""
处理不支持的数据类型,自定义Response
选择将列表转换为json字符串
"""
class Handle_list_to_json(Response):
"""不改变类的前提下,修改实例数据"""
@classmethod
def force_type(cls, response, environ=None):
"""列表类型修改为json
response:传入的实例数据,也就是不符合规范的数据"""
print(response)
if isinstance(response, list):
# 注意变量变量明必须对应force_type中的变量名
response = '+'.join(response)
return super().force_type(response,environ)
app.response_class = Handle_list_to_json
@app.route('/list_to_json/')
def dict_to_json():
user_information = ['python', 'java', 'c']
return Response(user_information)再次访问的时候会正确的返回列表为字符串
3.jsonify
会将数据类型转换为json
字符串
from flask import Flask,Response,jsonify
app = Flask(__name__)
@app.route('/json/<varriable>/')
def varriable_to_json(varriable):
a = [1, 2, 3]
b = (1, 2)
c = {'a':1, 'b':2}
a, b, c = jsonify(a), jsonify(b), jsonify(c)
if varriable == 'a':
return a
elif varriable == 'b':
return b
else:
return c
if __name__ == "__main__":
app.run(debug=True)
以上是关于Flask视图和URL的主要内容,如果未能解决你的问题,请参考以下文章