0x00 内容概览

  1. 请求解析
    1. 基本参数
    2. 必需参数
    3. 多值和列表
    4. 其他目标
    5. 参数位置
    6. 参数多个位置
    7. 高级类型处理
    8. 解析器继承
    9. 文件上传
    10. 错误处理
    11. 错误消息
  2. 参考链接

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:请求解析的更多相关文章

  1. Flask入门系列(转载)

    一.入门系列: Flask入门系列(一)–Hello World 项目开发中,经常要写一些小系统来辅助,比如监控系统,配置系统等等.用传统的Java写,太笨重了,连PHP都嫌麻烦.一直在寻找一个轻量级 ...

  2. flask的post,get请求及获取不同格式的参数

    flask的post,get请求及获取不同格式的参数 1 获取不同格式参数 1.0 获取json参数 Demo from flask import Flask, request, jsonify ap ...

  3. Flask开发系列之数据库操作

    Flask开发系列之数据库操作 Python数据库框架 我们可以在Flask中使用MySQL.Postgres.SQLite.Redis.MongoDB 或者 CouchDB. 还有一些数据库抽象层代 ...

  4. Flask开发系列之Web表单

    Flask开发系列之Web表单 简单示例 from flask import Flask, request, render_template app = Flask(__name__) @app.ro ...

  5. Flask开发系列之模板

    Flask开发系列之模板 本文对<FlaskWeb开发:基于python的Web应用开发实战>模板一节做的总结. Jinja2模板引擎 模板 模板是一个包含响应文本的文件,其中包含用占位变 ...

  6. Flask开发系列之Flask+redis实现IP代理池

    Flask开发系列之Flask+redis实现IP代理池 代理池的要求 多站抓取,异步检测:多站抓取:指的是我们需要从各大免费的ip代理网站,把他们公开的一些免费代理抓取下来:一步检测指的是:把这些代 ...

  7. Flask开发系列之快速入门

    Flask开发系列之快速入门 文档 一个最小的应用 调试模式 路由 变量规则 构造 URL HTTP 方法 静态文件 模板渲染 访问请求数据 环境局部变量 请求对象 文件上传 Cookies 重定向和 ...

  8. Android之三种网络请求解析数据(最佳案例)

    AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...

  9. Sharepoint学习笔记—习题系列--70-576习题解析 --索引目录

        Sharepoint学习笔记—习题系列--70-576习题解析  为便于查阅,这里整理并列出了70-576习题解析系列的所有问题,有些内容可能会在以后更新. 需要事先申明的是:     1. ...

随机推荐

  1. SEO百问

    SEO 的工作过程中,大家都会碰到很多这样或那样的问题,做 SEO 随着时间慢慢变长之后,知识会慢慢地积累,之前的问题也会慢慢的都被解答.这里是码动世界为大家整理的有关 SEO 百问百答. 1. 百度 ...

  2. Maven学习3(中央仓库)

    Maven项目在运行的时候,会首先找本地仓库是否有需要的jar,如果没有则去调用远程仓库. 解读Maven在仓库中的存储路径: 1.基于groupId准备路径,将句点分隔符转成路径分隔符,就是将  & ...

  3. 软件光栅器实现(四、OBJ文件加载)

    本节介绍软件光栅器的OBJ和MTL文件加载,转载请注明出处. 在管线的应用程序阶段,我们需要设置光栅器所渲染的模型数据.这些模型数据包括模型顶点的坐标.纹理.法线和材质等等,可以由我们手动编写,也可以 ...

  4. WEB服务器搭建(Apache+Tomcat+eclipse)

    1.下载xampp安装,选择Apache+MySQL+Tomcat 官方下载链接:https://www.apachefriends.org/zh_cn/download.html 2.下载安装jav ...

  5. cordova 问题汇总

    用chrome进行调试: https://jingyan.baidu.com/album/db55b609fde96d4ba30a2fa9.html?picindex=8 http://rensann ...

  6. javascript小括号、中括号、大括号学习总结

    作为一名编程人员,和括号打交道是必不可少的.你可知道在不同的上下文中,括号的作用是不一样的,今天就让我们简单总结下javascript小括号.中括号.大括号的用法. 总的来说,JavaScript中小 ...

  7. outlook VSTO

    https://files.cnblogs.com/files/maooveyu/OutlookPhotoSync.rar

  8. 《HTTP权威指南》1-HTTP概要

    Http HyperText Transfer Protocol,超文本协议通过此协议,我们可以将遍布全世界的Web服务器上的信息块快速,便捷,可靠的搬移到我们自己桌面上的Web浏览器上.这些信息块指 ...

  9. Openvswitch手册(8): ovs-vsctl的DB的操作

    ovs-vsctl的DB的操作 如果你在命令行里面找不到相应的命令创建和删除对象,则可以直接删除数据库 [−−if−exists] [−−columns=column[,column]...] lis ...

  10. [转]kaldi ASR: DNN训练

    作者:zqh_zy链接:http://www.jianshu.com/p/c5fb943afaba來源:简书著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 本文通过简单kaldi ...