【Flask-RESTPlus系列】Part3:请求解析
0x00 内容概览
- 请求解析
- 基本参数
- 必需参数
- 多值和列表
- 其他目标
- 参数位置
- 参数多个位置
- 高级类型处理
- 解析器继承
- 文件上传
- 错误处理
- 错误消息
- 参考链接
0x01 请求解析
注意:Flask-RESTPlus的整个请求解析器部分将被移除,并将替换成关于集成其他更善于处理输入、输出的包(例如marshmallow)的说明文档。但是考虑到已经被废弃,它将一直维护到2.0版本。如果你现在有代码使用它,并希望继续这样做,那么也无需担心,因为它不会很快消失。
Flask-RESTPlus的请求解析接口reqparse是模仿argparse接口实现的。它的设计目的是对Flask中flask.request对象上的任何变量提供简单和统一的访问方式。
1、基本参数
下面是一个请求解析器的简单示例。它在flask.Request.values字典中查找两个参数:一个整数和一个字符串:
from flask_restplus import reqparse parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate cannot be converted')
parser.add_argument('name') # Python3中默认类型为字符串
args = parser.parse_args()
注意:默认参数类型是unicode字符串。在Python3中为str类型,而在Python2中为unicode。
如果指定了help变量的值,那么在解析请求时,如果出现了类型错误,那么会将它渲染为错误信息。如果未指定help信息,那么默认的行为是返回类型错误信息本身。可以查看“11、错误信息”部分以了解更多细节。
注意:默认情况下,参数不是必需的。并且,如果请求中提供的某些参数不是RequestParser的部分内容,那么这些参数将会被忽略。
注意:请求解析器中声明的参数,如果在请求中并未设置这些参数值,那么它们将会默认设置为None。
2、必需参数
如果需要确保某个参数必须提供,那么可以在调用add_argument()时传入required=True的参数项:
parser.add_argument('name', required=True, help="Name cannot be blank!")
此时,如果请求中未提供该参数,那么将会返回错误信息。
3、多值和列表
如果想为某个key接受多个值以构成列表,那么可以传入action='append':
parser.add_argument('name', action='append')
此时的查询格式如下所示:
curl http://api.example.com -d "name=bob" -d "name=sue" -d "name=joe"
而程序中获取到的参数如下所示:
args = parser.parse_args()
args['name'] # ['bob', 'sue', 'joe']
如果期望一个逗号分隔的列表,那么可以使用action='split':
parser.add_argument('fruits', action='split')
此时的查询格式如下所示:
curl http://api.example.com -d "fruits=apple,lemon,cherry"
而程序中获取到的参数如下所示:
args = parser.parse_args()
args['fruits'] # ['apple', 'lemon', 'cherry']
4、其他目标
如果期望参数一旦被解析,就将其存储为其他名字,那么可以使用dest参数:
parser.add_argument('name', dest='public_name')
args = parser.parse_args()
args['public_name']
5、参数位置
默认情况下,RequestParser尝试从flask.Request.values和flask.Request.json中解析值。
在add_argument()中使用location参数来指定获取值的其他位置。可以使用flask.Request上的任何变量,例如:
# 仅仅在POST body中查找
parser.add_argument('name', type=int, location='form') # 仅仅在querystring中查找
parser.add_argument('PageSize', type=int, location='args') # 从请求头中查找
parser.add_argument('User-Agent', location='headers') # 从http cookies中查找
parser.add_argument('session_id', location='cookies') # 从上传文件中查找
parser.add_argument('picture', type=werkzeug.datastructures.FileStorage, location='files')
注意:当location='json'时只能使用type=list,点击此处查看更多。
注意:使用location='form'既能验证表单数据,又能为表单字段文档化。
6、参数多位置
为location参数赋一个列表就能为参数指定多个位置:
parser.add_argument('text', location=['headers', 'values'])
当指定多个参数位置时,那么所有指定位置的参数将会组成一个MultiDict。其中,列表中最后位置处的参数将会优先存储在结果集中。
如果参数位置列表中包含headers位置,那么参数名将变成对大小写敏感,并且必须匹配它们的标题大小写名称(见str.title())。
指定location='headers'(而不是作为列表的某个元素)将保留大小写不敏感的特性。
7、高级类型处理
有时,我们需要其他原始类型来处理输入验证问题。为此,inputs模块中提供了一些常用的类型处理方法,如下:
- boolean()用于广泛的布尔值处理
- ipv4()和ipv6()用于IP地址
- date_from_iso8601()和datetime_from_iso8601()用于ISO8601 date和datetime处理
只需要使用它们作为type参数的值即可:
parser.add_argument('flag', type=inputs.boolean)
查看inputs文档以了解所有可用的输入类型。
另外,我们也可以编写自己的输入类型:
def my_type(value):
'''解析类型'''
if not condition:
raise ValueError('This is not my type')
return parse(value) # Swagger文档化
my_type.__schema__ = {'type': 'string', 'format': 'my-custom-format'}
8、解析器继承
很多情况下,我们都需要为不同的资源指定不同的解析器。不过,如果这些不同的解析器之间存在大量相同的字段的话,将会存在大量重复编码的问题。为此,我们可以编写一个父解析器,父解析器中包含所有共同的参数,然后利用copy()方法来扩展解析器。另外,也可以利用replace_argument()来覆写父解析器中的任何参数,或者利用remove_argument()完全移除父解析器中的某个参数。例如:
from flask_restplus import reqparse parser = reqparse.RequestParser()
parser.add_argument('foo', type=int) parser_copy = parser.copy()
parser_copy.add_argument('bar', type=int)
# 此时,parser_copy中同时包含'foo'和'bar'参数 parser_copy.replace_argument('foo', required=True, location='json')
# 此时,'foo'参数变成了一个必需的str类型的参数,并且查找位置为json;而不再是父解析器中定义的int类型的可选参数 parser_copy.remove_argument('foo')
# 此时,parser_copy中不再包含'foo'参数
9、文件上传
为了利用RequestParser处理文件上传问题,我们需要将location变量值设置为files,并设置type值为FileStorage。如下所示:
from werkzeug.datastructures import FileStorage upload_parser = api.parser()
upload_parser.add_argument('file', location='files',
type=FileStorage, required=True) @api.route('/upload/')
@api.expect(upload_parser)
class Upload(Resource):
def post(self):
uploaded_file = args['file'] # 这是FileStorage实例
url = do_something_with_file(uploaded_file)
return {'url': url}, 201
10、错误处理
RequestParser处理错误的默认方式是在第一个错误产生时中断。当我们拥有需要花费一定时间来处理的参数时,这种方式是有好处的。然而,通常来说,将所有产生的错误都绑定在一起,然后同时一次性返回给客户端,这种方式则更加友好。这种方式既可以在Flask应用级别指定,也可以在特定的RequestParser实例级别指定。为了调用一个包含错误绑定选项的RequestParser,需要传入参数bundle_errors。例如:
from flask_restplus import reqparse parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True) # 如果某个请求中同时不包含'foo'和'bar',那么返回的错误将看起来如下所示: {
"message": {
"foo": "foo error message",
"bar": "bar error message"
}
} # 默认操作将仅仅返回第一个错误
parser = RequestParser()
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True) {
"message": {
"foo": "foo error message"
}
}
应用级别的配置key为“BUNDLE_ERRORS”。例如:
from flask import Flask app = Flask(__name__)
app.config['BUNDLE_ERRORS'] = True
警告:BUNDLE_ERRORS是一个全局设置,它将覆盖每个RequestParser实例中的bundle_errors选项值。
11、错误消息
每个字段的错误消息都可以通过在Argument(也包括RequestParser.add_argument)中使用help参数来自定义。
如果没有提供help参数,那么该字段的错误消息将会是类型错误本身的字符串表示。如果提供了help参数,那么错误消息将会是help参数的值。
help可能包含一个插入的符号{error_msg},它将会替换成类型错误的字符串表示。这种方式能够实现自定义错误消息,同时保留原始的错误消息。如下所示:
from flask_restplus import reqparse parser = reqparse.RequestParser()
parser.add_argument(
'foo',
choices=('one', 'two'),
help='Bad choice: {error_msg}'
) # 如果请求中的'foo'参数值为'three',那么错误信息将会如下所示:
{
"message": {
"foo": "Bad choice: three is not a valid choice",
}
}
0x02 参考链接
【Flask-RESTPlus系列】Part3:请求解析的更多相关文章
- Flask入门系列(转载)
一.入门系列: Flask入门系列(一)–Hello World 项目开发中,经常要写一些小系统来辅助,比如监控系统,配置系统等等.用传统的Java写,太笨重了,连PHP都嫌麻烦.一直在寻找一个轻量级 ...
- flask的post,get请求及获取不同格式的参数
flask的post,get请求及获取不同格式的参数 1 获取不同格式参数 1.0 获取json参数 Demo from flask import Flask, request, jsonify ap ...
- Flask开发系列之数据库操作
Flask开发系列之数据库操作 Python数据库框架 我们可以在Flask中使用MySQL.Postgres.SQLite.Redis.MongoDB 或者 CouchDB. 还有一些数据库抽象层代 ...
- Flask开发系列之Web表单
Flask开发系列之Web表单 简单示例 from flask import Flask, request, render_template app = Flask(__name__) @app.ro ...
- Flask开发系列之模板
Flask开发系列之模板 本文对<FlaskWeb开发:基于python的Web应用开发实战>模板一节做的总结. Jinja2模板引擎 模板 模板是一个包含响应文本的文件,其中包含用占位变 ...
- Flask开发系列之Flask+redis实现IP代理池
Flask开发系列之Flask+redis实现IP代理池 代理池的要求 多站抓取,异步检测:多站抓取:指的是我们需要从各大免费的ip代理网站,把他们公开的一些免费代理抓取下来:一步检测指的是:把这些代 ...
- Flask开发系列之快速入门
Flask开发系列之快速入门 文档 一个最小的应用 调试模式 路由 变量规则 构造 URL HTTP 方法 静态文件 模板渲染 访问请求数据 环境局部变量 请求对象 文件上传 Cookies 重定向和 ...
- Android之三种网络请求解析数据(最佳案例)
AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...
- Sharepoint学习笔记—习题系列--70-576习题解析 --索引目录
Sharepoint学习笔记—习题系列--70-576习题解析 为便于查阅,这里整理并列出了70-576习题解析系列的所有问题,有些内容可能会在以后更新. 需要事先申明的是: 1. ...
随机推荐
- SEO百问
SEO 的工作过程中,大家都会碰到很多这样或那样的问题,做 SEO 随着时间慢慢变长之后,知识会慢慢地积累,之前的问题也会慢慢的都被解答.这里是码动世界为大家整理的有关 SEO 百问百答. 1. 百度 ...
- Maven学习3(中央仓库)
Maven项目在运行的时候,会首先找本地仓库是否有需要的jar,如果没有则去调用远程仓库. 解读Maven在仓库中的存储路径: 1.基于groupId准备路径,将句点分隔符转成路径分隔符,就是将 & ...
- 软件光栅器实现(四、OBJ文件加载)
本节介绍软件光栅器的OBJ和MTL文件加载,转载请注明出处. 在管线的应用程序阶段,我们需要设置光栅器所渲染的模型数据.这些模型数据包括模型顶点的坐标.纹理.法线和材质等等,可以由我们手动编写,也可以 ...
- WEB服务器搭建(Apache+Tomcat+eclipse)
1.下载xampp安装,选择Apache+MySQL+Tomcat 官方下载链接:https://www.apachefriends.org/zh_cn/download.html 2.下载安装jav ...
- cordova 问题汇总
用chrome进行调试: https://jingyan.baidu.com/album/db55b609fde96d4ba30a2fa9.html?picindex=8 http://rensann ...
- javascript小括号、中括号、大括号学习总结
作为一名编程人员,和括号打交道是必不可少的.你可知道在不同的上下文中,括号的作用是不一样的,今天就让我们简单总结下javascript小括号.中括号.大括号的用法. 总的来说,JavaScript中小 ...
- outlook VSTO
https://files.cnblogs.com/files/maooveyu/OutlookPhotoSync.rar
- 《HTTP权威指南》1-HTTP概要
Http HyperText Transfer Protocol,超文本协议通过此协议,我们可以将遍布全世界的Web服务器上的信息块快速,便捷,可靠的搬移到我们自己桌面上的Web浏览器上.这些信息块指 ...
- Openvswitch手册(8): ovs-vsctl的DB的操作
ovs-vsctl的DB的操作 如果你在命令行里面找不到相应的命令创建和删除对象,则可以直接删除数据库 [−−if−exists] [−−columns=column[,column]...] lis ...
- [转]kaldi ASR: DNN训练
作者:zqh_zy链接:http://www.jianshu.com/p/c5fb943afaba來源:简书著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 本文通过简单kaldi ...