Flask学习笔记(2)
路由
在flask中,使用 @route()
装饰器来把函数绑定到URL。
@app.route('/home') #声明路由
def index(): # 声明视图函数
return '<h1>Hello, Flask!</h1>'
注意:路由和视图的名称必须全局唯一,不能出现重复。
除了可以使用装饰器的方式注册路由,还可以使用app的add_url_rule
方法。
def hello():
return 'Hello, Flask!'
app.add_url_rule('/hello', view_func=hello)
查询路由信息
有两种方式可以查看当前应用的路由信息
-
命令行方式
flask routes
输出内容如下:
Endpoint Methods Rule -------- ------- ----------------------- index GET / static GET /static/<path:filename>
-
在程序中获取
在应用的url_map属性中保存着当前flask应用所有的映射信息,可以读取这个属性获取路由信息
print(app.url_map)
遍历所有路由信息:
for rule in app.url_map.iter_rules(): print(rule.endpoint, rule.rule)
请求方式
路由默认的请求方式为
- GET
- OPTIONS
- HEAD
使用 methods
参数可以指定一个接口的请求方式
@app.route('/', methods=["POST"])
def hello_world():
return 'Hello World!'
蓝图
当flask程序越来越复杂,我们需要对程序进行模块化处理,在Flask中使用Blueprint来分模块组织管理。
蓝图可以理解为是一个存储一组视图方法的容器对象,其具有如下特点:
- 一个应用可以具有多个Blueprint。
- 可以将一个Blueprint注册到任何一个未使用的URL下,比如"/hello"、"/user"。
- Blueprint可以单独具有自己的模板、静态文件或者其他的通用的操作方法,它并不是必须要实现应用的视图和函数。
- 在一个应用初始化时,就应该注册需要使用的Blueprint。
使用方式
使用蓝图可以分为三个步骤:
- 创建一个蓝图对象
users/__init__.py
from flask import Blueprint
users_bp = Blueprint('users', __name__)
from . import views
- 在这个蓝图对象上进行操作,注册路由,指定静态文件夹,注册模板过滤器
users/views.py
@user_bp.route('/profile')
def get_profile():
return 'user profile!'
- 在应用对象上注册蓝图对象
app.py
app.register_blueprint(user_bp)
目录(包)的方式使用蓝图
对应一个打算包含多个文件的蓝图,可以将创建蓝图对象放到python包的 __init__.py
文件中
--------- project #工程目录
|------ app.py #启动文件
|------ users #用户蓝图
| |--- __init__.py #此处创建蓝图对象
| |...
|------ goods #商品蓝图
| |--- __init__.py
|...
示例:
新建包goods,__init__.py
文件内容如下
from flask import Blueprint
goods_bp = Blueprint('goods', __name__)
from . import views # 此处导入代码必须放在最后,如果放在最上方,会出现循环引用的问题
在goods目录下,新建 views.py
文件内容如下:
from . import goods_bp
@goods_bp.route('/goods')
def get_goods():
return 'get goods'
app.py内容如下:
from flask import Flask
from goods import goods_bp
app = Flask(__name__)
app.register_blueprint(goods_bp)
if __name__ == '__main__':
app.run()
蓝图内部静态文件
和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由,需要我们在创建时指定 static_folder
参数。
示例:
goods_bp = Blueprint('goods', __name__, static_folder='static_file', template_folder='goods_templates')
app.register_blueprint(goods_bp, url_prefix='/goods')
转换器
动态路由
通过把 URL 的一部分标记为 <variable_name>
就可以在 URL 中添加变量。标记的部分会作为关键字参数传递给函数。通过使用 <converter:variable_name>
,可以选择性的加上一个转换器,为变量指定规则。
from flask import Flask
app = Flask(__name__)
@app.route('/users/<user_id>')
def hello_world(user_id):
print(type(user_id)) # <class 'str'>
return 'users {} '.format(user_id)
if __name__ == '__main__':
app.run(debug=True)
此处 user_id
作为参数名传入视图,默认为字符串类型。
默认转换器
除了默认的字符串类型之外,Flask还提供了如下其他类型的转换器。
DEFAULT_CONVERTERS = {
"default": UnicodeConverter,
"string": UnicodeConverter,
"any": AnyConverter,
"path": PathConverter,
"int": IntegerConverter,
"float": FloatConverter,
"uuid": UUIDConverter,
}
转换器对应的含义:
转换器 | 含义 |
---|---|
default | 接受字符串,默认转换器 |
string | 接受字符串,跟默认一样 |
any | 限定url中接收参数的值 |
path | 可以接受斜线 |
int | 接受整数 |
float | 接受浮点数 |
uuid | 只接收uuid类型的字符串 |
示例:
@app.route('/users/<path:user_id>')
def hello_world(user_id):
print(type(user_id))
return 'users {} '.format(user_id)
自定义转换器
当系统提供的转换器并不能满足我们的要求时,此时我们需要自定义转换器。需要用到Flask的转换器基类BaseConverter
自定义转换器主要做3步:
-
创建转换器类
from werkzeug.routing import BaseConverter class MobileConverter(BaseConverter): regex = r'1[3-9]\d{9}' # 转换器的正则规则
注意:regex名字是固定的
-
将转换器添加到converters中
app.url_map.converters['mobile'] = MobileConverter
-
使用自定义的转换器
@app.route('/message/<mobile:mobile_num>') def send_message(mobile_num): print(type(mobile_num)) return 'mobile num {} '.format(mobile_num)
Request
如果想要获取其他地方的参数,可以通过Flask提供的全局对象 request
来获取。request
中不同的属性对应不同位置的请求参数。
常见的属性和说明如下:
属性 | 说明 |
---|---|
data | 记录请求的数据,并转换为字符串 |
form | 请求中的表单数据 |
args | 请求中的查询参数 |
cookies | 请求中的cookie信息 |
headers | 请求中的报文头 |
method | 请求使用的HTTP方法 |
url | 记录请求的URL地址 |
files | 请求上传的文件 |
示例:
@app.route('/users')
def get_user_id():
user_id = request.args.get('user_id')
return 'your user id is {} '.format(user_id)
接受上传文件示例:
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['file']
# with open('./test.png', 'wb') as new_file:
# new_file.write(file.read())
file.save('./test.png') # 可以直接调用save方法保存
return 'ok'
模板
在项目的目录下新建名为templates
的文件夹,并在此文件夹下新建名为index.html
的html文件。
内容如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>我的模板内容</h1>
名字: <span>{{ name }}</span> <br>
年龄: <span>{{ age }}</span> <br>
</body>
</html>
渲染数据到模板
@app.route('/')
def home():
uname = '张三'
uage = '20'
return render_template('index.html', name=uname, age=uage)