作者:mobiledu2502894753 | 来源:互联网 | 2023-10-16 21:42
Problem explanation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| python
from marshmallow import Schema, fields, validate, validates, validates_schema, ValidationError
class IntRangeSchema(Schema):
first = fields.Integer(required=True)
last = fields.Integer(required=True)
class PoolSchema(Schema):
name = fields.String(required=True)
ranges = fields.List(fields.Nested(IntRangeSchema))
('ranges')
def validate_ranges(self, ranges):
print 'validate_ranges %s' % repr(ranges) |
When I load valid data, the validate_ranges() is called with a list of dictionaries (which is expected):
1 2 3 4 5 6 7 8 9 10 11 12
| python
schema = PoolSchema(strict=True)
data = {
'name': 'pool1',
'ranges': [
{'first': 1, 'last': 10},
{'first': 11, 'last': 20},
],
}
print repr(schema.load(data).data)
# => validate_ranges [{'last': 10, 'first': 1}, {'last': 20, 'first': 11}]
# => {'ranges': [{'last': 10, 'first': 1}, {'last': 20, 'first': 11}], 'name': u'pool1'} |
But when I load an invalid data, then the validates_ranges() receives only a non-valid dictionary, not a list:
1 2 3 4 5 6 7 8 9 10 11
| python
data = {
'name': 'pool2',
'ranges': [
{'first': 1, 'last': 10},
{'last': 10},
],
}
print repr(schema.load(data).data)
# => validate_ranges {'last': 10}
# => ... ValidationError |
Moreover, if I add complete schema validation (via
), this is what passed to it:
1
| {'ranges': {'last': 10}, 'name': u'pool2'} |
I see multiple problems here:
1) naive deserialization in List field type
2) running validations for fields that have already failed by other means.
The second issue is addressed in https://github.com/marshmallow-code/marshmallow/issues/323, so I'll focus on the first one.
Let's take List field as example. Deserialization of list types is basically:
1 2 3
| python
def _deserialize(self, value, attr, data):
return [self.container.deserialize(each) for each in value] |
By definition container is a field type which will report deserialization/validation errors by raise ValidationError exceptions. That means that you will get an error for the first invalid item in the list and the rest of items won't be validated at all. The proper way would be to accumulate all errors:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| python
def _deserialize(self, value, attr, data):
if not utils.is_collection(value):
self.fail('invalid')
result = []
errors = {}
for idx, each in enumerate(value):
try:
result.append(self.container.deserialize(each))
except ValidationError as e:
result.append(e.data)
errors.update({str(idx): e.message})
if errors:
raise ValidationError(errors, data=result)
return result |
该提问来源于开源项目:marshmallow-code/marshmallow
Thank you for the detailed report.
I think collecting errors is the desired and expected behavior. I would gladly review and merge a PR for this.