15

In Marshmallow in order to have a list field you can use:

include_in = fields.List(cls_or_instance=fields.Str(),
                         default=['sample1', 'sample2'])

This is OK, but I have a new requirement to have a list of dictionaries in a field. A sample payload:

[{
  "name": "Ali",
  "age": 20
},
{
  "name": "Hasan",
  "age": 32
}]

This payload is part of the bigger schema, so now the question is how should I add and validate such a field?


EDIT-1: I went a step further and could find out that there is a Dict field type in Marshmallow so until now I have the below code sample:

fields.List(fields.Dict(
        keys=fields.String(validate=OneOf(('name', 'age'))),
        values=fields.String(required=True)
))

Now new problem arise and I cannot set different data types for fields in the dictionary (name and age). I'd be happy if someone could shed some light on this.

Alireza
  • 6,497
  • 13
  • 59
  • 132
  • You may want to look into https://github.com/Bachmann1234/marshmallow-polyfield or https://github.com/marshmallow-code/marshmallow-oneofschema, which both implement polymorphic fields, i.e. you can use a different schemas for different data shapes. – Steve L Aug 13 '19 at 03:53

2 Answers2

19

If the items in the list have the same shape, you can use a nested field within fields.List, like so:

class PersonSchema(Schema):
    name = fields.Str()
    age = fields.Int()

class RootSchema(Schema):
    people = fields.List(fields.Nested(PersonSchema))
Steve L
  • 1,704
  • 1
  • 20
  • 29
2

Another approach for validating list of dictionaries in a field using one schema class.

from marshmallow import Schema, ValidationError


class PeopleSchema(Schema):
    name = fields.Str(required=True)
    age = fields.Int(required=True)


people = [{
    "name": "Ali",
    "age": 20
},
{
    "name": "Hasan",
    "age": 32
},
{
    "name": "Ali",
    "age": "twenty"  # Error: Not an int
}
]


def validate_people():
    try:
        validated_data = PeopleSchema(many=True).load(people)
    except ValidationError as err:
        print(err.messages)

validate_people()

Output:

{2: {'age': ['Not a valid integer.']}}
Shakeel
  • 1,869
  • 15
  • 23