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. MacBook上那些好用的工具们

    https://blog.csdn.net/qq_33833327/article/details/78454703

  2. Python基础环境搭建

    一.编程语言 1.解释型语言:每执行一次程序就要将代码翻译一次,如Java.JavaScript.VBScript.Perl.Python.Ruby.MATLAB 等都是解释型语言 2.编译型语言:程 ...

  3. 跨域资源共享(CROS)

    跨域资源共享(CROS) 同源策略(Same Origin Policy, SOP) 同源策略允许运行在页面的脚本可以无限制的访问同一个网站(同源)中其他脚本的任何方法和属性.当不同网站页面(非同源) ...

  4. Python是一门什么样的语言

    先做个总结:Python是一门动态解释型的强类型定义语言. 那何为动态?何为解释?何为强类型呢? 我们需要了解编译型和解释型.静态语言和动态语言.强类型定义语言和弱类型定义语言这6个概念就可知晓. 编 ...

  5. 【python-时间戳】时间与时间戳之间的转换

    对于时间数据,如2016-05-05 20:28:54,有时需要与时间戳进行相互的运算,此时就需要对两种形式进行转换,在Python中,转换时需要用到time模块,具体的操作有如下的几种: 将时间转换 ...

  6. poj3660 cow contest

    这题主要是传递闭包 题意: n头牛,m次测试,假设a牛赢过b牛,那么说明a牛的能力比b牛强,问你根据输入的m次测试结果,最多能确定多少条牛的排名 大题的思路: 对于 k 牛,比他强的有x头牛,比他弱的 ...

  7. Shell编写字符菜单管理-8

    第8章 Shell编写字符菜单管理 一.shell函数定义function menu(){ echo 'this is a func!!';} 二.shell函数使用menu 三.cat命令的here ...

  8. JS获取对象数据类型的方法

    1.typeof: 语法:typeof 对象 或者 typeof(对象) 返回对象的数据类型:只有原始数据类型:boolean number string undefined function obj ...

  9. MFC之几类消息的区别

    1.ON_COMMAND与ON_UPDATE_COMMAND_UI 开发MFC程序,给菜单子项添加消息处理函数时,会碰到ON_COMMAND和ON_UPDATE_COMMAND_UI两个消息. ON_ ...

  10. Reids学习1 -- 初识Redis

    1. Reids和其他类型数据库对比 名称 类型 数据库存储选项 查询类型 附加功能 Redis 使用内存存储的非关系数据库 字符串,列表,集和,散列表,有序集合 每个类型有自己的专属命令,还有批量操 ...