不管我们做什么应用,只要和用户输入打交道,就有一个原则–永远不要相信用户的输入数据。意味着我们要对用户输入进行严格的验证,web开发时一般输入数据都以JSON形式发送到后端API,API要对输入数据做验证。一般我都是加很多判断,各种if,导致代码很丑陋,能不能有一种方式比较优雅的验证用户数据呢?Schema就派上用场了。
安装
pip install schema
Schema
基本类型:满足条件后会返回当前的值,不满足将报错!
from schema import Schema
print Schema(int).validate(10) # 10
print Schema(int).validate('10') # schema.SchemaUnexpectedTypeError
list/tuple/set:只需满足list/tuple/set
中的其中一个条件后会返回当前的值,不满足将报错!!
from schema import Schema
print Schema([int, float]).validate([1, 2, 3, 3.3]) # [1, 2, 3, 3.3]
print Schema([int, float]).validate([1, 2, 3, 4]) # [1, 2, 3, 4]
print Schema([int, float]).validate(['a', 'b', 'c', 'd']) # schema.SchemaError
字典:首先,模型字典与数据字典的Key是否完全一样,不一样将报错;而后,那数据字典的value验证模型字典相应的value,如果验证通过才会返回数据,否则将会报错
from schema import Schema
print Schema({"name": str, "age": int}).validate({"name": "laozhang", "age": 18}) # {'age': 18, 'name': 'laozhang'}
print Schema({"name": str, "age": int}).validate({"name": "laozhang"}) # schema.SchemaMissingKeyError
print Schema({"name": str, "age": int}).validate({"name": 18, "age": 18}) # schema.SchemaError
print Schema({"name": str, "age": int}).validate({"name": 18, "age": 18, "addr": "广东"}) # schema.SchemaWrongKeyError
有个概念值得注意:Schema
传入的字典,我们通常称之为模型字典,validate
传入的字典,我们通常称之为数据字典
可调用的对象:满足可调用的对象的条件后会返回当前的值,不满足将报错!
from schema import Schema
print Schema(lambda x: 1 < x < 8).validate(5) # 5
print Schema(lambda x: 1 < x < 8).validate(8) # schema.SchemaError
Use
Use
在验证的时候,会自动帮你转换它的值
from schema import Schema, Use
print Schema(Use(int)).validate(10) # 10-->int类型
print Schema(Use(int)).validate('10') # 10-->int类型
print Schema(Use(int)).validate('xiaoming') # schema.SchemaError
Const
我们知道Use
在验证的时候,会自动帮你转换它的值。Const
可以保持原始数据不变:
from schema import Schema, Use, Const
print Schema(Const(Use(int))).validate('10') # 10-->str类型
And
And
对是否满足多个条件进行验证
from schema import Schema, And
print Schema(And(int, lambda x: x < x < 8)).validate(5) # 5
print Schema(And(int, lambda x: x < x < 8)).validate(8) # schema.SchemaError
print Schema(And(int, lambda x: x < x < 8)).validate('5') # schema.SchemaError
Or
Or
对是否满足其中一个条件进行验证
from schema import Schema, Or, Use
print Schema(Or(lambda x: 1 < x < 8, Use(int))).validate(5) # 5-->int类型
print Schema(Or(lambda x: 1 < x < 8, Use(int))).validate(8) # 8-->int类型
print Schema(Or(lambda x: 1 < x < 8, Use(int))).validate('8') # 8-->int类型
print Schema(Or(lambda x: 1 < x < 8, Use(int))).validate('xiaoming') # schema.SchemaError
Optional
Schema
传入字典进行验证很好用,可是常常因为传入的字典与模型字典key不匹配,从而导致报错,此时我们可以使用Optional
进行可选验证字典:
from schema import Schema, Optional
print Schema({"name": str, Optional("age"): int}).validate({"name": "laozhang"}) # {'name': 'laozhang'}
print Schema({"name": str, Optional("age"): int}).validate({"name": "laozhang", "age": 18}) # {'age': 18, 'name': 'laozhang'}
print Schema({"name": str, Optional("age"): int}).validate({"name": 18, "age": 18}) # schema.SchemaError
print Schema({"name": str, Optional("age"): int}).validate({"name": "laozhang", "age": 18, "addr": "广东"}) # schema.SchemaWrongKeyError
我们还可以在Optional
中设置一个默认值,如下:
print Schema({"name": str, Optional("age", default=18): int}).validate({"name": "laozhang"}) # {'age': 18, 'name': 'laozhang'}
上面这种方式只是用于数据字典的key比模型字典的key少的情况,如果数据字典的key比模型字典的多,那么又该如何进行忽略验证呢?我们可以使用ignore_extra_keys
参数,并将其设置为True,如下:
from schema import Schema
print Schema({"name": str, "age": int}, ignore_extra_keys=True).validate({"name": "laozhang", "age": 18, "addr": "广东"}) # {'age': 18, 'name': 'laozhang'}
Forbidden
Forbidden
可以将某个key禁止:
from schema import Schema, Forbidden
print Schema({Forbidden('name'): str, 'age': int}).validate({"age": 15}) # {"age": 15}
print Schema({Forbidden('name'): str, 'age': int}).validate({"name": "laozhang", "age": 15}) # schema.SchemaForbiddenKeyError
print Schema({Forbidden('name'): str, 'age': int}).validate({"name": 10, "age": 15}) # schema.SchemaWrongKeyError
值得注意的是,与禁用秘钥配对的值将决定了它是否会被拒绝:
from schema import Schema, Forbidden
print Schema({Forbidden('name'): int, 'name': str}).validate({'name': 'laozhang'}) # {'name': 'laozhang'}
print Schema({Forbidden('name'): str, 'name': str}).validate({'name': 'laozhang'}) # schema.SchemaForbiddenKeyError
另外,Forbidden
的优先级要比Optional
要高:
from schema import Schema, Forbidden, Optional
print Schema({Forbidden('name'): str, Optional('name'): str}).validate({"name": "laozhang"}) # schema.SchemaForbiddenKeyError
Regex
Regex
可以根据正则表达式进行匹配验证
import re
from schema import Regex
print Regex('^foo').validate('football') # football
print Regex('^foo').validate('basketball') # schema.SchemaError
# flags=re.I忽略大小写
print Regex('[A-Z]+', flags=re.I).validate('football') # football
当然,Regex
同样也可以配合Schema
一起使用:
from schema import Schema, Regex
print Schema(Regex('^foo')).validate('football') # football
自定义错误
Schema
、And
、Or
、Use
等类都有一个参数error
,可以自定义错误信息:
from schema import Schema
print Schema(int, error='只能是整数类型').validate('abc') # schema.SchemaUnexpectedTypeError: 只能是整数类型