使用 voluptuous 校验数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
在 Python 中,我们经常需要对参数进行校验,这是我们有好多种方法,例如写很多 if 啊,或者写正则表达式啊等等,技巧高的人可以写得很巧妙,而技巧一般的人呢,可能会写得很冗长,例如我,经常就不能很好得处理参数校验的代码。
所以我就不断得寻找,终于最近发现了一个不错的 python 参数校验 lib,叫做 voluptuous。名字可能有点难记,而且英文翻译过来的中文还不怎么好听,但是非常好用。下面就逐渐带大家尝试一下 voluptuous 库的妙用。
<br>安装 voluptuous
 
要用之前,肯定要先安装的啦,安装这一步很简单,还是按照往常一般使用 pip 搞定。我使用的是当前的最新版 0.8.8:
 
pip install voluptuous==0.8.8
 
尝试 voluptuous
 
首先,想来一个最为常见的,就是校验参数的类型,我这里假设参数都是以 json 格式进行传递的,json 格式在 python 中又可以表现为字典(dict),所以这里就不做区分了。
以官网的日志为例,使用分页的参数为例子,校验参数的类型,首先,我们要求参数的类型,查询的字段q必须为字符串,分页大小per_page必须为数字,页码page必须为数字。
那么,使用 voluptuous 后,可以这样写:
 
from voluptuous import Schema
 
s = Schema({
 
    'q': str,
 
    'per_page': int,
 
    'page': int
 
})
 
这就表示了我们刚才的需求:查询的字段q必须为字符串,分页大小per_page必须为数字,页码page必须为数字。
那么,现在,假设客户端传过来了一组参数:
 
{"q": "hello",
 
"page": 10,
 
"per_page": 20
 
}
 
那么,我们要怎么来校验呢?也很简单:
 
from voluptuous import Schema
 
s = Schema({
 
    'q': str,
 
    'per_page': int,
 
    'page': int
 
})
 
  
 
print s({"q": "hello",
 
         "page": 10,
 
         "per_page": 20
 
        })
 
  
 
这里可以看到,我们使用客户端传递过来的参数作为参数,调用了我们使用既定模板创建的对象,然后直接把他打印出来,如果你跑过这段代码,你会发现结果如下:
 
{"q": "hello",
 
"page": 10,
 
"per_page": 20
 
}
 
没错, voluptuous 就是将校验通过的参数返回了。就是这么简单。
 
那这时,你可能要问了,如果校验不通过的参数怎么办,我要怎么处理,下面就演示一下如果传递的参数是:
 
{"q": "hello",
 
"page": "world",
 
"per_page": 20
 
}
 
这样的话,要怎么来处理校验不通过的问题,其实,当校验不通过的时候,Schema 会抛出一个异常,然后我们可以通过捕获这个异常来确定校验失败的问题,例如:
try:
 
    print s({"q": "hello", "page": "world","per_page": 20})
 
except MultipleInvalid as e:
 
    print "error: {} occur while parse args".format(e.errors)
 
当你执行这段代码之后,你会发现打印出来的内容是:
 
error: [TypeInvalid('expected int',)] occur while parse args
我们就知道参数是有问题的,需要客户端确认。
 
更进一步
 
ok,这就是一个简单的校验,下面我们进行更复杂的校验,我们现在不仅要保证参数的类型正确,我们还需要保证查询参数一定要有,另外两个参数可有可无。那么我们可以怎么做呢?
 
其实,也很简单,就是给必须的参数加上一个 Required 关键字,例如这样:
from voluptuous import Schema, Required
 
required_s = Schema({
 
    Required('q'): str,
 
    'per_page': int,
 
    'page': int
 
})
 
然后,我们可以尝试一下加入什么都不传,会发生什么事:
try:
 
    print required_s({})
 
except MultipleInvalid as e:
 
    print "error: {} occur while parse with required args".format(e.errors)
 
很明显,你跑一遍就知道了,这段代码会抛出这个异常:
 
error: [RequiredFieldInvalid('required key not provided',)] occur while parse with required args
 
这个时候,我们再贪心一点,我们觉得参数必须还不够,还不能有多余的参数,什么参数都塞过来,浪费我内存啊,过滤这个应该和刚才的参数必须有一样简单吧?
是的,不过这时因为不是对单独一个参数起作用了,所以需要放在 Schema 的参数里面,这个参数叫做 extras,例如下面这段就是表示不要多余的参数:
 
not_allow_extra_s = Schema({
 
    'q': str,
 
    'per_page': int,
 
    'page': int
 
}, extra=False)
 
然后我们尝试一下:
try:
 
    print not_allow_extra_s({"q": "hello", "unknown": "key"})
 
except MultipleInvalid as e:
 
    print "error: {} occur while parse with no extras args".format(e.errors)
 
结果也很简单:
error: [Invalid('extra keys not allowed',)] occur while parse with no extras args
 
其实,Schema 默认就是不允许有多余参数的,如果我们想要多余的参数,则需要显式得将这个参数设置为 True,表示允许有多余的参数。
现在我们已经知道一些用法了,但是,我们觉得只控制类型不够,我们还想控制一下参数的长度,例如查询的参数不能超过 10 个字符,那么样怎么做了?
 
下面这段代码就自定义了一个校验值不能超过 10 个字符的 str 类型:
 
def less_than_10(value):
 
    if isinstance(value, str) and len(value)
 
校验函数很简单,接受一个参数,也就是要校验的值,然后,如果校验成功就返回这个值,否则就抛出一个 Invalid 的异常。这样 Schema 就知道是否校验通过了。
其实,你可能会想,如果这里校验通过后我返回的不是参数的值会怎样?如果你有这个想法,我很佩服。
确实,如果这里不返回参数的值,Schema 也会认为是校验通过的,而且 Schema 会将你的返回值返回。那么想到这里,你是不是有一些更加强大的想法?好吧,不知道你有没有,我这里告知一下,可以通过这个方法来进行数据转换。
假如,我们的查询只支持大写字母,但是我们认为客户端传过来是小写字母的时候也是有效的,那么,我们就需要将客户端传递过来的参数进行转换,转成大写字母,那么,我们可以这样写:
 
def convert_letter(value):
 
    if isinstance(value, str):
 
        return value.upper()
 
    raise Invalid("not valid string")
 
  
 
transformation_s = Schema({
 
    Required('q'): convert_letter,
 
    'per_page': int,
 
    'page': int
 
})
 
print transformation_s({'q': 'hello'})
然后,我们看一下输出:
 
{'q': 'HELLO'}
 
已经变成了大写了。
 
好吧,到此已经将 voluptuous 的一些比较常用和重要的功能介绍完了,如果大家有用心去体会的话,相信可以写出一些非常精妙的校验器出来。

  

posted @   狂师  阅读(1044)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2013-06-26 LoadRunner监控Unix、Windows方法及常用性能指标
2013-06-26 Ubuntu下使用rpm 软件包
点击右上角即可分享
微信分享提示