Flask
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架。
Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL。
其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。
官网: https://flask.palletsprojects.com/en/1.1.x/
官方文档: http://docs.jinkan.org/docs/flask/
Flask常用第三方扩展包:
- Flask-SQLalchemy:操作数据库,ORM;
- Flask-script:终端脚本工具,脚手架;
- Flask-migrate:管理迁移数据库;
- Flask-Session:Session存储方式指定;
- Flask-WTF:表单;
- Flask-Mail:邮件;
- Flask-Bable:提供国际化和本地化支持,翻译;
- Flask-Login:认证用户状态;
- Flask-OpenID:认证, OAuth;
- Flask-RESTful:开发REST API的工具;
- Flask JSON-RPC: 开发rpc远程服务[过程]调用
- Flask-Bootstrap:集成前端Twitter Bootstrap框架
- Flask-Moment:本地化日期和时间
- Flask-Admin:简单而可扩展的管理接口的框架
可以通过 https://pypi.org/search/?c=Framework+%3A%3A+Flask 查看更多flask官方推荐的扩展
一、准备
mkvirtualenv flask -p python3
![](https://i-blog.csdnimg.cn/blog_migrate/02aa0e65bae96068d49dee6aade73c1e.png#pic_center)
二、安装
pip install flask==0.12.5
![](https://i-blog.csdnimg.cn/blog_migrate/d0ee7579a730dbd8cb69b272532f3448.png#pic_center)
三、创建flask项目
与django不同,flask不会提供任何的自动操作,所以需要手动创建项目目录,需要手动创建启动项目的管理文件
![](https://i-blog.csdnimg.cn/blog_migrate/29e7b6c509bc5e7f686bf076578a2dcf.png#pic_center)
创建一个flask框架的主程序。名字可以是app.py/run.py/main.py/index.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "<h1>python31</h1>"
if __name__ == '__main__':
app.run()
1.flask基本运行
from flask import Flask
# 创建应用对象
app = Flask(__name__)
# 视图加载
@app.route(rule="/") # 声明路由
def index(): # 声明视图函数
return "<h1>python31</h1>" # 直接通过return返回普通字符串
if __name__ == '__main__':
# 启动项目,不要在run 后面写任何代码,不会被执行到
app.run(debug=True, port=8000, host='0.0.0.0') # wsgiref模块提供的
2.flask快速使用
from flask import Flask
# 1. 实例化flask 应用对象
app = Flask(__name__)
# 2. 编写视图和路由
@app.route(rule="/", methods=['get']) # 声明路由
def index():
return "<h1>hello flask</h1>"
if __name__ == '__main__':
# 启动项目,不要在run 后面写任何代码,不会被执行到
app.run(debug=True, port=8000, host='0.0.0.0')
3.flask加载配置
from flask import Flask
# 1. 实例化flask 应用对象
app = Flask(__name__)
# 1.1 配置信息
class Config():
# 配置项目运行在debug调试模式下
DEBUG = True
# 1.2 加载配置到应用对象中
app.config.from_object(Config)
# 2. 编写视图和路由
@app.route(rule="/", methods=['get'])
def index():
return "<h1>python31</h1>"
if __name__ == '__main__':
app.run()
四、路由的基本定义
路由和视图的名称必须全局唯一,不能出现重复,否则报错。
url中可以传递路由参数, 2种方式
路由参数就是url路径的一部分。
1.任意路由参数接收
from flask import Flask
# 创建应用对象
app = Flask(__name__)
# 加载配置
class Config():
DEBUG = True
app.config.from_object(Config)
# 路由: 一种访问地址[url]和应用程序[视图]进行一对一绑定的映射关系
# 往往在开发中,我们所说的路由,其实通常指代完成路由绑定关系的路由类
@app.route(rule="/user/<user_id>-<mobile>") # 可以指定一个或多个参数进行传递
def index(user_id, mobile): # 这里的参数名称必须和路由上面的保持一致
return "user_id=%s,mobile=%s" % (user_id, mobile)
if __name__ == '__main__':
app.run()
2.限定路由参数接收
通过路由转换器限定路由参数的类型,flask系统自带转换器编写在werkzeug.routing.py文件中。底部可以看到以下字典:
DEFAULT_CONVERTERS = {
"default": UnicodeConverter,
"string": UnicodeConverter,
"any": AnyConverter,
"path": PathConverter,
"int": IntegerConverter,
"float": FloatConverter,
"uuid": UUIDConverter,
}
系统自带的转换器具体使用方式在每种转换器的注释代码中有写,请留意每种转换器初始化的参数。
转换器名称 | 描述 |
---|---|
string | 默认类型,接受不带斜杠的任何文本 |
int | 接受正整数 |
float | 接受正浮点值 |
path | 接收string 但也接受斜线 |
uuid | 接受UUID(通用唯一识别码)字符串 xxxx-xxxx-xxxxx-xxxxx |
代码:
from flask import Flask
# 创建应用对象
app = Flask(__name__)
# 加载配置
class Config():
DEBUG = True
app.config.from_object(Config)
@app.route(rule="/", methods=['get'])
def index():
return "<h1>hello flask</h1>"
@app.route(rule="/user/<float:user_id>") # 使用flask内置的路由参数转换器限定参数的类型,int, flask, string ....
def user(user_id):
print(user_id)
return "<h1>hello user</h1>"
if __name__ == '__main__':
app.run()
3.自定义路由参数转换器
也叫正则匹配路由参数.
在 web 开发中,可能会出现限制用户访问规则的场景,那么这个时候就需要用到正则匹配,根据自己的规则去限定请求参数再进行访问
具体实现步骤为:
- 导入转换器基类:在 Flask 中,所有的路由的匹配规则都是使用转换器对象进行记录
- 自定义转换器:自定义类继承于转换器基类
- 添加转换器到默认的转换器字典中
- 使用自定义转换器实现自定义匹配规则
当前此处定义的规则是:手机号码
代码:
from flask import Flask
# 实例化flask 应用对象
app = Flask(__name__)
# 自定义路由参数转换器
# 1. 引入BaseConverter路由参数转换器基类
from werkzeug.routing import BaseConverter
# 2. 自定义路由参数转换器
class MobileConverter(BaseConverter):
regex = r'1[3-9]\d{9}'
def __init__(self, map, *args, **kwargs):
super().__init__(map, *args, **kwargs)
# 3. 注册路由参数转换到app应用对象中
app.url_map.converters['mobile'] = MobileConverter
# 编写视图和路由
@app.route(rule="/user/<mobile:user_mobile>")
def user(user_mobile):
print(user_mobile)
return "<h1>hello user</h1>"
# url_map是flask路由列表对象,类似之前在django里面的urlpatterns
if __name__ == '__main__':
app.run()
4.自定义转换器
from flask import Flask
# 创建应用对象
app = Flask(__name__)
# 加载配置
class Config():
DEBUG = True
app.config.from_object(Config)
# 自定义路由转换器
# 1. 声明的路由转换器类必须直接或间接继承于BaseConverter
from werkzeug.routing import BaseConverter
class MobileConverter(BaseConverter):
# 2. 必须在初始化中调用父类对象进行初始化
def __init__(self, *args, **kwargs):
# 3. regex必须有参数
self.regex = r'1[3-9]\d{9}'
super().__init__(*args, **kwargs)
# 4. 注册
# app.url_map.converters['使用别名'] = 转换器类名
app.url_map.converters['mob'] = MobileConverter
# 路由转换器对路由参数的类型进行限定
@app.route(rule="/<mob:user_id>")
def index(user_id):
print(type(user_id))
return "user_id=%s" % user_id
if __name__ == '__main__':
app.run()
5.路由限定请求方式
from flask import Flask
app = Flask(__name__)
# 路由转换器对路由参数的类型进行限定
# @app.route(rule="/") # 没有填写第二个参数methods则默认只能通过get请求访问
@app.route(rule="/", methods=['POST', 'PUT', 'PATCH', 'DELETE'])
def index():
return "ok"
if __name__ == '__main__':
app.run(debug=True)
6.注册路由和视图代码进行分离处理
from flask import Flask
app = Flask(__name__)
def index():
return "ok"
# 也可以让路由注册和视图进行分离
app.add_url_rule(rule='/', view_func=index)
if __name__ == '__main__':
app.run(debug=True)
五、http的请求与响应
1.请求
文档: http://docs.jinkan.org/docs/flask/api.html#flask.request
- request:flask中代表当前请求的
request 对象
- 作用:在视图函数中取出本次请求数据
- 导入:
from flask import request
- 代码位置:from flask.app import Request
常用的属性如下:
属性 | 说明 | 类型 |
---|---|---|
data | 记录请求体的数据,并转换为字符串 只要是通过其他属性无法识别转换的请求体数据 最终都是保留到data属性中 | bytes类型 |
form | 记录请求中的html表单数据 | MultiDict |
args | 记录请求中的查询字符串,也可以是query_string | MultiDict |
cookies | 记录请求中的cookie信息 | Dict |
headers | 记录请求中的请求头 | EnvironHeaders |
method | 记录请求使用的HTTP方法 | GET/POST |
url | 记录请求的URL地址 | string |
files | 记录请求上传的文件列表 | * |
json | 记录ajax请求的json数据 | json |
from flask import Flask
# 实例化flask 应用对象
app = Flask(__name__)
# 编写视图和路由
from flask import request
from urllib.parse import parse_qs
@app.route(rule='/user', methods=['get', 'post', 'put', 'patch', 'delete'])
def user():
print(request.method) # 获取本次客户端的http请求方法 GET
print(request.path) # 获取本次客户端请求的路由路径部分[去掉域名端口] /user
print(request.url) # 获取本次客户端请求的http url地址 http://127.0.0.1:5000/user?user=1
# 获取查询字符串
print(request.query_string) # 获取本次客户端的(原始)查询字符串 b'user=1'
query_string = parse_qs(request.query_string)
print(query_string) # {b'lve': [b'swimming', b'pingpang']}
# print(query_string["lve".encode()][0].decode())
print(request.args) # 获取本次客户端的(Dict字典)查询字符串 from collections import OrderedDict
print(request.args.get('lve')) # 提取一个值
print(request.args.getlist('lve')) # 提取多个值
print(request.args.to_dict()) # {'lve': 'swimming'}
"""
ImmutableMultiDict的实例对象 提供了四个常用的方法给我们获取数据,
1. get 获取指定参数的第一个值
2. getlist 获取指定参数的多个值
3. to_dict 把所有参数转换成字典[request对象的部分属性不支持]
4. to_list 把所有参数转换成列表[request对象的部分属性不支持]
"""
# 获取html表单,视图必须支持post方法访问
print(request.form) # 表单中的全部数据
print(request.form.get('username')) # 表单单个数据
# 获取ajax或者表单中的上传文件都需要使用request.files
print(request.files.get('avatar')) # <FileStorage: '2.jpg' ('image/jpeg')>
# 获取json数据
print(request.json) # {'username': 'xiaohuihui'}
# 获取请求头
print(request.headers)
print(request.headers.to_list()) # 获取请求头
print(request.headers.get('Host')) # 获取请求头,REMOTE_ADDR客户端的地址
print(request.headers.get('Company')) # 获取自定义请求头,首字母大写
# 其他属性
print(request.is_json) # 是否是ajax请求
return "<h1>hello user</h1>"
if __name__ == '__main__':
app.run(debug=True)
请求中的html表单数据
from flask import Flask, request
app = Flask(__name__)
@app.route('/form', methods=['POST', 'PUT', 'PATCH'])
def get_form():
print(request) # HTTP请求处理对象
# 接受表单数据
print(request.form)
"""打印效果:
ImmutableMultiDict([('username', 'xiaoming'), ('password', '123456'), ('lve', 'swimming'), ('lve', 'game'), ('lve', 'shopping')])
# ImmutableMultiDict 这个类就是一个字典的子类,我们可以称之为类字典对象,所以可以通过字典的操作来使用。
# 思路来源: from collection import OrderedDict
"""
# 获取指定键的单个值
print(request.form.get('username'))
print(request.form['username'])
print(request.form['lve']) # 如果键对应的数据有多个值,则不能通过get或中括号
# 获取指定键获取多个值
print(request.form.getlist('lve')) # ['swimming', 'game', 'shopping']
# 格式转换
# ImmutableMultiDict 转换成基本格式
# 注意: 转换过程中,如果出现一个键对应多个值的情况,则取第一个值
ret = request.form.to_dict() # {'username': 'xiaoming', 'password': '123456', 'lve': 'swimming'}
return 'ok'
if __name__ == '__main__':
app.run(debug=True)
来自客户端请求的其他数据
from flask import Flask, request
app = Flask(__name__)
@app.route('/query')
def get_query_params():
# 获取查询字符串 query_params
print(request.args)
"""打印效果:
ImmutableMultiDict([('username', 'xiaoming'), ('age', '18')])
"""
print(request.args.to_dict()) # {'username': 'xiaoming', 'age': '18'}
return 'ok'
@app.route('/head')
def get_head():
"""获取请求头数据"""
print(request.headers)
print(request.headers["Content-Type"]) # application/x-www-form-urlencoded
# 获取自定义请求头[首字母大写,不支持多个单词使用横杠进行拼接的写法,也不支持多字节字符]
print(request.headers["Company"]) # boy
return 'ok'
@app.route('/', methods=['POST', 'GET'])
def index():
print(request.method) # GET 获取本次客户端的请求方法名
print(request.url) # http://127.0.0.1:5000/ url地址
print(request.json) # {'pay_type': 1, 'credit': 0, 'coupon': 0} 获取json数据
print(request.files) # ImmutableMultiDict([('video1', <FileStorage: 'demo.mp4' ('video/mp4')>)])
print(request.files.get('video1'))
return 'ok'
if __name__ == '__main__':
app.run(debug=True)
2.响应
flask默认支持2种响应方式:
数据响应: 默认响应html文本,也可以返回 JSON格式,或其他格式
页面响应: 重定向
url_for 视图之间的跳转
响应的时候,flask也支持自定义http响应状态码
from flask import Flask
# 实例化flask 应用对象
app = Flask(__name__)
# 编写视图和路由
from flask import make_response, jsonify, request
@app.route(rule='/user', methods=['get', 'post'])
def user():
# 返回html文本
# 默认直接可以通过return直接返回html文本格式
# return "<h1>hello user</h1>"
# return make_response('<h1>hello user</h1>') # 等同于上面的一段
# 返回json数据
# data = {"username":"小明","age":17,"sex": True}
# 识别身份
if request.args.get('user') == 'abc':
# 也可以返回图片,压缩包 等其他在浏览器能支持的数据,既可以支持显示图片,也可以支持显示
with open('2.jpg', 'rb') as f:
content = f.read()
response = make_response(content)
response.headers['Content-Type'] = 'image/jpeg'
return response
else:
return '没有权限'
# 支持下载
# with open('123.zip', 'rb') as f:
# response.headers['Content-Type'] = 'application/zip'
# return response
@app.route('/')
def index():
return "<img src='user?user=abc'>"
if __name__ == '__main__':
app.run(debug=True)
页面响应和自定义响应
from flask import Flask, redirect, url_for
# 实例化flask 应用对象
app = Flask(__name__)
# 编写视图和路由
# redirect 实际上就是Response响应类的实例对象
from flask import make_response
@app.route(rule='/')
def index():
# 页面跳转
# return redirect('http://www.baidu.com') # 跳转到站外
# return redirect('/user') # 跳转到站内
# return redirect(url_for('user', user_id=100)) # 通过url_for指定视图名称,直接找到对应路由进行跳转
# 跳转的原理,实际就是利用HTML文档中的元信息
response = make_response()
response.headers['Location'] = "http://www.baidu.com"
response.headers['Company'] = 'boy' # 自定义响应头
response.status_code = 302 # 自定义响应状态码
return response
@app.route('/user12344')
def user():
return "用户中心"
if __name__ == '__main__':
app.run(debug=True)
重定向跳转
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/index')
def index():
return 'index'
# 转内跳转,进行视图之间的跳转
@app.route('/')
def home():
# 视图之间的跳转
return redirect(url_for('index', name='xiaoming'))
# 跳转到站外地址
@app.route('/go')
def go():
return redirect('http://www.baidu.com')
if __name__ == '__main__':
app.run(debug=True)