Python marshmallow`validate_schema`拒绝带有`pass_many=True'的未知字段`
当Python marshmallow`validate_schema`拒绝带有`pass_many=True'的未知字段`,python,marshmallow,Python,Marshmallow,当模式被传递给一个要验证的对象列表时,我很难理解如何处理未知字段。我到目前为止: class MySchema(Schema): # fields ... @marshmallow_decorators.validates_schema(pass_original=True) def check_unknown_fields(self, data, original_data): if isinstance(original_data, list):
模式
被传递给一个要验证的对象列表时,我很难理解如何处理未知字段。我到目前为止:
class MySchema(Schema):
# fields ...
@marshmallow_decorators.validates_schema(pass_original=True)
def check_unknown_fields(self, data, original_data):
if isinstance(original_data, list):
for dct in original_data:
self._assert_no_unknown_field(dct)
else:
self._assert_no_unknown_field(original_data)
def _assert_no_unknown_field(self, dct):
unknown = set(dct.keys()) - set(self.fields)
if unknown:
raise MarshmallowValidationError('Unknown field', unknown)
但这显然不起作用,因为每次都会对列表中的所有项运行验证器。因此,将捕获第一个错误,并返回所有项目:
items = [
{'a': 1, 'b': 2, 'unknown1': 3},
{'a': 4, 'b': 5, 'unknown2': 6},
]
errors = MySchema(many=True).validate(items)
# {0: {'unknown1': ['Unknown field']}, 1: {'unknown1': ['Unknown field']}}
我试图想办法只从data
参数对应的original_data
中获取单个项目,并只验证其中一个,但我真的无法做到这一点,因为项目没有id,或者没有可以使其可搜索的字段
我错过什么了吗?有解决办法吗?这是我想出的一个解决办法。。。我希望它更简单,但这里是:
from marshmallow import Schema, ValidationError as MarshmallowValidationError, fields
UNKNOWN_MESSAGE = 'unknown field'
class _RejectUnknownMixin(object):
def _collect_unknown_fields_errors(self, schema, data):
"""
Checks `data` against `schema` and returns a dictionary `{<field>: <error>}`
if unknown fields detected, or `{0: {<field>: <error>}, ... N: <field>: <error>}`
if `data` is a list.
"""
if isinstance(data, list):
validation_errors = {}
for i, datum in enumerate(data):
datum_validation_errors = self._collect_unknown_fields_errors(schema, datum)
if datum_validation_errors:
validation_errors[i] = datum_validation_errors
return validation_errors
else:
unknown = set(data.keys()) - set(schema.fields)
return {name: [UNKNOWN_MESSAGE] for name in unknown}
class NestedRejectUnknown(fields.Nested, _RejectUnknownMixin):
"""
Nested field that returns validation errors if unknown fields are detected.
"""
def _deserialize(self, value, attr, data):
validation_errors = {}
try:
result = super(NestedRejectUnknown, self)._deserialize(value, attr, data)
except MarshmallowValidationError as err:
validation_errors = err.normalized_messages()
# Merge with unknown field errors
validation_errors = _merge_dicts(
self._collect_unknown_fields_errors(self.schema, value), validation_errors)
if validation_errors:
raise MarshmallowValidationError(validation_errors)
return result
class SchemaRejectUnknown(Schema, _RejectUnknownMixin):
"""
Schema that return validation errors if unknown fields are detected
"""
def validate(self, data, **kwargs):
validation_errors = super(SchemaRejectUnknown, self).validate(data, **kwargs)
return _merge_dicts(
self._collect_unknown_fields_errors(self, data), validation_errors)
def _merge_dicts(a, b, path=None):
"""
Ref : https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge
merges b into a
"""
if path is None:
path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
_merge_dicts(a[key], b[key], path + [str(key)])
elif a[key] == b[key]:
# same leaf value
pass
else:
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
else:
a[key] = b[key]
return a
从marshmallow导入架构,ValidationError作为MarshmallowValidationError,字段
未知消息='未知字段'
类_RejectUnknownMixin(对象):
定义\u收集\u未知\u字段\u错误(自身、架构、数据):
"""
根据“schema”检查“data”,并返回字典“{:}”`
如果检测到未知字段,或`{0:{:},…N:}`
如果'data'是一个列表。
"""
如果存在(数据、列表):
验证_错误={}
对于i,枚举中的数据(数据):
数据\验证\错误=自身。\收集\未知\字段\错误(模式、数据)
如果数据\验证\错误:
验证错误[i]=基准验证错误
返回验证错误
其他:
unknown=set(data.keys())-set(schema.fields)
为未知}中的名称返回{name:[UNKNOWN_MESSAGE]
类NestedRejectUnknown(fields.Nested,_RejectUnknownMixin):
"""
如果检测到未知字段,则返回验证错误的嵌套字段。
"""
def_反序列化(self、value、attr、data):
验证_错误={}
尝试:
结果=超级(NestedRejectUnknown,self)。\u反序列化(值、属性、数据)
除MarshmallowValidationError作为错误外:
验证\u错误=err.normalized\u消息()
#合并未知字段错误
验证\u错误=\u合并\u指令(
self.\u收集\u未知\u字段\u错误(self.schema、值)、验证\u错误)
如果验证错误:
引发MarshmallowValidationError(验证错误)
返回结果
类SchemaRejectUnknown(Schema,\u RejectUnknownMixin):
"""
如果检测到未知字段,则返回验证错误的架构
"""
def验证(自身、数据、**kwargs):
验证_errors=super(SchemaRejectUnknown,self)。验证(数据,**kwargs)
返回\u合并\u命令(
self.\u收集\u未知\u字段\u错误(self、数据)、验证\u错误)
定义合并命令(a,b,路径=无):
"""
裁判:https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge
将b合并为a
"""
如果路径为“无”:
路径=[]
对于b键:
如果输入a:
如果isinstance(a[键],dict)和isinstance(b[键],dict):
_合并指令(a[键]、b[键]、路径+[键])
如果a[键]==b[键]:
#相同叶值
通过
其他:
引发异常(“%s”%”处发生冲突。加入(路径+[str(键)])
其他:
a[键]=b[键]
归还
这是我想出的一个解决办法。。。我希望它更简单,但这里是:
from marshmallow import Schema, ValidationError as MarshmallowValidationError, fields
UNKNOWN_MESSAGE = 'unknown field'
class _RejectUnknownMixin(object):
def _collect_unknown_fields_errors(self, schema, data):
"""
Checks `data` against `schema` and returns a dictionary `{<field>: <error>}`
if unknown fields detected, or `{0: {<field>: <error>}, ... N: <field>: <error>}`
if `data` is a list.
"""
if isinstance(data, list):
validation_errors = {}
for i, datum in enumerate(data):
datum_validation_errors = self._collect_unknown_fields_errors(schema, datum)
if datum_validation_errors:
validation_errors[i] = datum_validation_errors
return validation_errors
else:
unknown = set(data.keys()) - set(schema.fields)
return {name: [UNKNOWN_MESSAGE] for name in unknown}
class NestedRejectUnknown(fields.Nested, _RejectUnknownMixin):
"""
Nested field that returns validation errors if unknown fields are detected.
"""
def _deserialize(self, value, attr, data):
validation_errors = {}
try:
result = super(NestedRejectUnknown, self)._deserialize(value, attr, data)
except MarshmallowValidationError as err:
validation_errors = err.normalized_messages()
# Merge with unknown field errors
validation_errors = _merge_dicts(
self._collect_unknown_fields_errors(self.schema, value), validation_errors)
if validation_errors:
raise MarshmallowValidationError(validation_errors)
return result
class SchemaRejectUnknown(Schema, _RejectUnknownMixin):
"""
Schema that return validation errors if unknown fields are detected
"""
def validate(self, data, **kwargs):
validation_errors = super(SchemaRejectUnknown, self).validate(data, **kwargs)
return _merge_dicts(
self._collect_unknown_fields_errors(self, data), validation_errors)
def _merge_dicts(a, b, path=None):
"""
Ref : https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge
merges b into a
"""
if path is None:
path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
_merge_dicts(a[key], b[key], path + [str(key)])
elif a[key] == b[key]:
# same leaf value
pass
else:
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
else:
a[key] = b[key]
return a
从marshmallow导入架构,ValidationError作为MarshmallowValidationError,字段
未知消息='未知字段'
类_RejectUnknownMixin(对象):
定义\u收集\u未知\u字段\u错误(自身、架构、数据):
"""
根据“schema”检查“data”,并返回字典“{:}”`
如果检测到未知字段,或`{0:{:},…N:}`
如果'data'是一个列表。
"""
如果存在(数据、列表):
验证_错误={}
对于i,枚举中的数据(数据):
数据\验证\错误=自身。\收集\未知\字段\错误(模式、数据)
如果数据\验证\错误:
验证错误[i]=基准验证错误
返回验证错误
其他:
unknown=set(data.keys())-set(schema.fields)
为未知}中的名称返回{name:[UNKNOWN_MESSAGE]
类NestedRejectUnknown(fields.Nested,_RejectUnknownMixin):
"""
如果检测到未知字段,则返回验证错误的嵌套字段。
"""
def_反序列化(self、value、attr、data):
验证_错误={}
尝试:
结果=超级(NestedRejectUnknown,self)。\u反序列化(值、属性、数据)
除MarshmallowValidationError作为错误外:
验证\u错误=err.normalized\u消息()
#合并未知字段错误
验证\u错误=\u合并\u指令(
self.\u收集\u未知\u字段\u错误(self.schema、值)、验证\u错误)
如果验证错误:
引发MarshmallowValidationError(验证错误)
返回结果
类SchemaRejectUnknown(Schema,\u RejectUnknownMixin):
"""
如果检测到未知字段,则返回验证错误的架构
"""
def验证(自身、数据、**kwargs):
验证_errors=super(SchemaRejectUnknown,self)。验证(数据,**kwargs)
返回\u合并\u命令(
self.\u收集\u未知\u字段\u错误(self、数据)、验证\u错误)
定义合并命令(a,b,路径=无):
"""
裁判:https://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge
将b合并为a
"""
如果路径为“无”:
路径=[]
对于b键:
如果输入a:
如果isinstance(a[键],dict)和isinstance(b[键],dict):
_合并指令(a[键]、b[键]、路径+[键])
如果a[键]==b[键]:
#相同叶值