工作中需要对如下json结构进行验证:
"ActiveStatus" : [
{
"effectiveDates" : {
"effectiveFrom" : "2018-05-10T12:44:17Z",
"effectiveTo" : "2018-05-11T00:29:29Z"
},
"status" : "Active",
"reason" : ""
},
{
"effectiveDates" : {
"effectiveFrom" : "2018-05-11T00:29:29Z"
},
"status" : "Inactive",
"reason" : "Expired/Matured"
}
],
使用cerberus, 定位到schema list.
(一)先从单条记录开始测试(cerberus_test_single.py)
from cerberus import Validator from datetime import datetime, date, time def string_toDatetime(string): return datetime.strptime(string, "%Y-%m-%d") schema={ 'effectiveDates':{ 'type':'dict', 'schema':{ 'effectiveFrom':{'type':'datetime'}, 'effectiveTo':{'type':'datetime'} } }, 'status':{'type':'string','allowed':['Active','Inactive']}, 'reason':{'type':'string'} } document={ 'effectiveDates':{ 'effectiveFrom':string_toDatetime('2018-05-10'), 'effectiveTo':string_toDatetime('2018-05-11'), }, 'status':'Active', 'reason':'Expired' } v=Validator(schema) v.validate(document) print(v.errors)
在命令行运行文件,验证成功:
E:\Learning\AWS\cerberus>cerberus_test.py
{}
注:结果为{}表示v.errors中没有错误,即验证成功。
如果修改上述文件中的document为如下:
document={ 'effectiveDates':{ 'effectiveFrom':string_toDatetime('2018-05-10'), 'effectiveTo':string_toDatetime('2018-05-11'), }, 'status':'ctive', 'reason':'Expired' }
此时将验证失败:
E:\Learning\AWS\cerberus>cerberus_test_single.py {'status': ['unallowed value ctive']}
(二)加入list, 验证多条的情况:
首先想到将上述schema(红色部分)嵌套到一个schema里,然后type指定list:
schema={ 'type':'list' schema={ 'effectiveDates':{ 'type':'dict', 'schema':{ 'effectiveFrom':{'type':'datetime'}, 'effectiveTo':{'type':'datetime'} } }, 'status':{'type':'string','allowed':['Active','Inactive']}, 'reason':{'type':'string'} } }
代码如下(cerberus_test.py)
from cerberus import Validator from datetime import datetime, date, time def string_toDatetime(string): return datetime.strptime(string, '%Y-%m-%d') schema={ 'activeStatus':{ 'type':'list', 'schema':{ 'effectiveDates':{ 'type':'dict', 'schema':{ 'effectiveFrom':{'type':'datetime'}, 'effectiveTo':{'type':'datetime'} } }, 'status':{'type':'string','allowed':['Active','Inactive']}, 'reason':{'type':'string','allowed':['Expired','Matured']} } } } document={ 'activeStatus':[ { 'effectiveDates':{ 'effectiveFrom':string_toDatetime('2018-05-10'), 'effectiveTo':string_toDatetime('2018-05-11') }, 'status':'Active', 'reason':'Expired' }, { 'effectiveDates' : { 'effectiveFrom' :string_toDatetime('2018-05-11') }, 'status' : 'Inactive', 'reason' : 'Matured' } ] } v=Validator(schema) v.validate(document) print(v.errors)
命令行运行代码发现:
E:\Learning\AWS\cerberus>cerberus_test.py Traceback (most recent call last): File "E:\Learning\AWS\cerberus\test.py", line 48, inv.validate(document) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 877, in validate self.__validate_definitions(definitions, field) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 940, in __validate_definitions result = validate_rule(rule) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 922, in validate_rule return validator(definitions.get(rule, None), field, value) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 1234, in _validate_schema self.__validate_schema_sequence(field, schema, value) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 1259, in __validate_schema_sequence update=self.update, normalize=False) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 877, in validate self.__validate_definitions(definitions, field) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 940, in __validate_definitions result = validate_rule(rule) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 921, in validate_rule validator = self.__get_rule_handler('validate', rule) File "C:\Python27\lib\site-packages\cerberus\validator.py", line 338, in __get_rule_handler "domain.".format(rule, domain)) RuntimeError: There's no handler for 'status' in the 'validate' domain.
(三)解决办法:
仔细查看cerberus自带例子(http://docs.python-cerberus.org/en/stable/validation-rules.html#schema-list)
>>> schema = {'rows': {'type': 'list', ... 'schema': {'type': 'dict', 'schema': {'sku': {'type': 'string'}, ... 'price': {'type': 'integer'}}}}} >>> document = {'rows': [{'sku': 'KT123', 'price': 100}]} >>> v.validate(document, schema) True
发现它把schema又嵌入到一个shema里,而不是我想的那样,于是我这么做:
schema={ 'activeStatus':{ 'type':'list', 'schema':{ 'schema':{ 'effectiveDates':{ 'type':'dict', 'schema':{ 'effectiveFrom':{'type':'datetime'}, 'effectiveTo':{'type':'datetime'} } }, 'status':{'type':'string','allowed':['Active','Inactive']}, 'reason':{'type':'string','allowed':['Expired','Matured']} } } } }
竟然可以成功验证!以下为完整的python文件(cerberus_test.py):
from cerberus import Validator from datetime import datetime, date, time #import pdb def string_toDatetime(string): return datetime.strptime(string, '%Y-%m-%d') schema={ 'activeStatus':{ 'type':'list', 'schema':{ 'schema':{ 'effectiveDates':{ 'type':'dict', 'schema':{ 'effectiveFrom':{'type':'datetime'}, 'effectiveTo':{'type':'datetime'} } }, 'status':{'type':'string','allowed':['Active','Inactive']}, 'reason':{'type':'string','allowed':['Expired','Matured']} } } } } document={ 'activeStatus':[ { 'effectiveDates':{ 'effectiveFrom':string_toDatetime('2018-05-10'), 'effectiveTo':string_toDatetime('2018-05-11') }, 'status':'Active', 'reason':'Expired' }, { 'effectiveDates' : { 'effectiveFrom' :string_toDatetime('2018-05-11') }, 'status' : 'Inactive', 'reason' : 'Matured' } ] } #pdb.set_trace() v=Validator(schema) v.validate(document) print(v.errors)
注意:因为schema是list,document在构建的时候需要使用数组[]。