23

I want a Marshmallow Schema with the following output json -

{
  "_id": "aae216334c3611e78a3e06148752fd79",
  "_time": 20.79606056213379,
  "more_data" : {...}
}

Marshmallow doesn't serialize private members so this is as close as I can get -

class ApiSchema(Schema):
    class Meta:
        strict = True

    time = fields.Number()
    id = fields.String()

But I do need the underscores in the output json.

Is there a way to tell Marshmallow to serialize the fields using different names?

selotape
  • 846
  • 1
  • 13
  • 26

4 Answers4

32

The accepted answer (using attribute) didn't work for me, possibly because:

Note: This should only be used for very specific use cases such as outputting multiple fields for a single attribute. In most cases, you should use data_key instead.

However data_key worked nicely:

class ApiSchema(Schema):
    class Meta:
        strict = True

    _time = fields.Number(data_key="time")
    _id = fields.String(data_key="id")
johndodo
  • 17,247
  • 15
  • 96
  • 113
24

https://marshmallow.readthedocs.io/en/2.x-line/quickstart.html#specifying-attribute-names

Even though the docs are for version 2, this seems to still work as of 3.5.1. The stable version 3 docs will not have this example.

class ApiSchema(Schema):
  class Meta:
      strict = True

  _time = fields.Number(attribute="time")
  _id = fields.String(attribute="id")
dtc
  • 1,774
  • 2
  • 21
  • 44
  • 2
    careful: https://github.com/marshmallow-code/marshmallow/issues/837 https://marshmallow.readthedocs.io/en/stable/upgrading.html?highlight=data_Key#load-from-and-dump-to-are-merged-into-data-key – lupodellasleppa Apr 13 '21 at 13:10
11

The answer's well documented in Marshmallows api reference.

I need to use dump_to :

class ApiSchema(Schema):
    class Meta:
        strict = True

    time = fields.Number(dump_to='_time')
    id = fields.String(dump_to='_id')
selotape
  • 846
  • 1
  • 13
  • 26
2

You can override the dump method to prepend underscores to selected fields before returning the serialised object:

class ApiSchema(Schema):
    class Meta:
        strict = True

    time = fields.Number()
    id = fields.String()

    def dump(self, *args, **kwargs):
        special = kwargs.pop('special', None)
        _partial = super(ApiSchema, self).dump(*args, **kwargs)
        if special is not None and all(f in _partial for f in special):
            for field in special:
                _partial['_{}'.format(field)] = _partial.pop(field)
        return _partial

api_schema = ApiSchema(...)
result = api_schema.dump(obj, special=('id', 'time'))

You can also use the post_dump decorator on a separate custom method without having to override dump, but then, you may have to hardcode the fields to-be-modified as part of the class, which may be inflexible depending on your use case.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139