Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

marshmallow flatten nested objects

I have objects that look a little something like:

source = {
  id: 123,
  objects: [
    {
      random_data: aaaa,
      actual_data: {
        useful: 111,
        ...
      }
    }, 
    {
      random_data: bbbb,
      actual_data: {
        useful: 222,
        ...
      }
    }
  ]
}

and while I could easily serialize that as is, it would be far more useful to transform it into the following format:

dest = {
  id: 123,
  objects: [
    {
      useful: 111,
      ...
    },
    {
      useful: 222,
      ...
    }
  ]
}

Given I already have a schema for the innermost object (actual_data in the source above - it is a lot more complex than my example shows), what is the best way of flattening that nested object so I only get the objects from actual_data without the extra depth? I would have thought it would be something like

objects = Nested(UsefulSchema, many=True, load_from"<something>.useful_data")

but I have been unable to find a solution without preprocessing the data.

NB I have simplified my example a lot to give the simplest form of my problem. In my actual code, the source data is a large list of similar objects from sqlalchemy.

like image 688
user user user Avatar asked Feb 23 '18 15:02

user user user


1 Answers

For marshmallow version >= 3 (Python 3)

You can achieve this by using Pluck fields to allow the parent to get data from its child.

class ActualDataSchema(ModelSchema):
    useful = fields.String()
    also_useful = fields.String()

class ObjectSchema(ModelSchema):
    useful = fields.Pluck(ActualDataSchema, 'useful')
    also_useful = fields.Pluck(ActualDataSchema, 'also_useful')

class DestSchema(ModelSchema):
    id = fields.Integer()
    objects = fields.Nested(ObjectSchema, many=True)

For marshmallow version < 3 (Python 2)

You have to use Method or Function fields instead.

class ObjectSchema(ModelSchema):
    useful = fields.Function(lambda obj: obj.actual_data.useful)
    also_useful = fields.Function(lambda obj: obj.actual_data.also_useful)

class DestSchema(ModelSchema):
    id = fields.Integer()
    objects = fields.Nested(ObjectSchema, many=True)

More info

  • For another example of this exact problem that's a bit more fleshed out and involves SQLAlchemy and Flask, see my other answer here.
  • documentation for fields.Pluck()
  • documentation for fields.Function() and fields.Method()
like image 51
MarredCheese Avatar answered Sep 18 '22 21:09

MarredCheese