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. VS2017 带参数启动调式程序

    有些程序,比如FFPlay,需要传递命令行参数才能运行想要的功能,比如字幕, ffplay -vf subtitles=mv.mkv mv.mkv 参数是 -vf subtitles=mv.mkv m ...

  2. iBtais 多重嵌套循环

    iBatis支持集合循环, 但是如何做到双重循环, 请见下例子 例子描述: 需要去三张结构相同的表中获取信息, 需要将信息拼合去重后返回 入参数据类型: Map<String,Object> ...

  3. p112 the podocyte

    正常人尿液只有一很少的蛋白质.尿蛋白特别是白蛋白的出现,是肾小球疾病的重要特征,也是众多肾脏疾病的关键的诊断标记,包括了统计数据或者说经济效应上都很重要的那些肾病.糖尿病肾病等等.可能没被广泛认识的是 ...

  4. flask上下文详解

    一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...

  5. 【病毒分析】对一个vbs脚本病毒的分析

    [病毒分析]对一个vbs脚本病毒的分析 本文来源:i春秋社区-分享你的技术,为安全加点温度 一.前言 病毒课老师丢给我们一份加密过的vbs脚本病毒的代码去尝试分析,这里把分析过程发出来,供大家参考,如 ...

  6. Windows下编译安装 FFmpeg

    在Linux/Mac下编译 ffmpeg是非常方便的.但要在 Windows下编译 ffmpeg还真要花点时间.以下就是在 Windowns下编译ffmpeg的步骤: 一.安装Cygwin 在wind ...

  7. centos7换源

    cd /etc/yum.repos.d/ #打开源目录 mv /CentOS-Base.repo /CentOS-Base.repo.bak #备份原来的源wget -O /etc/yum.repos ...

  8. 5.AutoCompleteTextView、自定义广播

    新建信息 布局:自动出来的是系统的组件,里面是listview,写ontextchanglis也行 <LinearLayout xmlns:android="http://schema ...

  9. HTTP 协议中 GET 和 POST 方法详解

    GET请求报文分析 1.请求行 请求方法 GET(描述该请求采用了什么请求方法),HTTP 1.0 和 1.1 协议中共包含10种请求方法.不过 HTTP 1.1 中只有8种方法. URI 请求WEB ...

  10. Spark基础-scala学习(七、类型参数)

    类型参数是什么 类似于java泛型,泛型类 泛型函数 上边界Bounds 下边界 View Bounds Context Bounds Manifest Context Bounds 协变和逆变 Ex ...