Search code examples
python-3.xdictionaryflaskflask-sqlalchemymarshmallow

How do I serialise a nested dictionary with Marshmallow?


I'm new to marshmallow and flask etc. I'm trying to learn by creating an API that consumes a jsonified python dictionary. The dictionary contains nested dictionaries like this. It also contains a few Null items.

{
    "TITLE": "XXX",
    "NAME": "Mongoose",
    "TIME": "0430",
    "USED": null,
    "DESCRIPTION": "",
    "WEAPONS": {
        "HEAT": "Israel",
        "RADAR": "Flat",
        "CONV": {
            "S": true,
            "N": false,
            "A": false
         },
    },
}

I simply want to consume this back into a dictionary type. Something like this on the POST action

fields_schema = FieldSchema(many=True)
field_schema = FieldSchema()

json_data = request.get_json(force=True)
if not json_data:
    return {'message': 'No input data provided'}, 400
# Validate and deserialize input
try:
    data = field_schema.load(json_data)
except ValidationError as e:
    return e.messages, 422

Where data would simply be a nested dictionary.

It is defining the schema class that is causing me problems. From what I can tell, when defining the schema, marshmallow doesnt have a JSON type and when I use fields.Dict I get the following error:

{
    "meta": [
        "Missing data for required field."
    ],
    "TITLE": [
        "Unknown field."
    etc...

I'm not sure whether I should be looking at using a nested Schema or whether I am totally over complicating things.

My fields_schema currently looks like this:

class FieldSchema(ma.Schema):
    id = fields.Integer()
    meta = fields.Dict(required=True)

Any pointers would be greatly appreciated


Solution

  • If you're going to validate the nested object, you can use Marshmallow's fields.Nested functionality.

    Using their example

    from marshmallow import Schema, fields, pprint
    
    class UserSchema(Schema):
        name = fields.String()
        email = fields.Email()
        created_at = fields.DateTime()
    
    class BlogSchema(Schema):
        title = fields.String()
        author = fields.Nested(UserSchema)
    
    user = User(name="Monty", email="[email protected]")
    blog = Blog(title="Something Completely Different", author=user)
    result = BlogSchema().dump(blog)
    pprint(result)
    # {'title': u'Something Completely Different',
    #  'author': {'name': u'Monty',
    #             'email': u'[email protected]',
    #             'created_at': '2014-08-17T14:58:57.600623+00:00'}}
    

    Your need to define a schema from the root document though. Something like

    class Widget(Schema):
        TITLE = fields.String()
        NAME = fields.String()
        # ...
        WEAPONS = fields.Nested(Weapon)
    
    class Weapon(Schema):
        HEAT = fields.String()
        # ...
    

    might get you going.