Have a nested schema using a list field and trying to make it required. A normal field within the same nested schema will enforce required just fine. The documentation states the list field inherits the same kwargs.
Here's a stripped down version:
class Links(Schema):
states = fields.List(fields.String(), required=True) # Does not work
region = fields.Integer(required=True) # Works fine
class Job(Schema):
id = fields.Integer()
links = fields.Nested(Links)
I've also tried putting the required kwarg at the list string field level too.
Hope I have not overlooked something. The more I dug the more it started to look like a bug. Thank you!
Thanks for reporting! I will look into this soon.
@morgan Can you give an example input where the required validation is not working?
@sloria Sure thing. The list is empty, flagged as required and no error is produced:
{
"jobs": {
"links": {
"states": []
}
}
}
@morgan Thanks for clarifying. The behavior you are seeing is the expected--though perhaps not the desired--behavior. required=True validates the _presence_ of the field in the input dictionary; it does not validate whether the input list is empty or not.
Inconsistency in validating empty values was noted for string fields in #76 and is addressed in 2.0.0 (see http://marshmallow.readthedocs.org/en/dev/upgrading.html#deserializing-empty-values-allow-none-and-allow-blank).
I think it would make sense to add an allow_empty param to List as well.
If i understand the problem right:
from marshmallow import Schema, fields, validate
class Links(Schema):
states = fields.List(fields.String(), required=True, validate=validate.Length(min=1))
region = fields.Integer(required=True)
class Job(Schema):
id = fields.Integer()
links = fields.Nested(Links)
Job().load({
"links": {
"states": [],
"region": 1
}
})
# UnmarshalResult(data={'links': None}, errors={'links': {'states': [u'Shorter than minimum length 1.']}})
Thanks @rastikerdar -- that is the right approach; We probably don't need to introduce the allow_empty parameter, as you can achieve the same validation using validate.Length
not_empty = validate.Length(min=1, error='Field cannot be empty.')
states = fields.List(fields.Str(), required=True, validate=not_empty)
@morgan Does that meet your use case?
@sloria I see. The required=True is indicating simply that the key needs to be set but doesn't care if the value(s) are empty.
Thank you for providing more clarity!
Most helpful comment
If i understand the problem right: