Search code examples
pythonmarshmallow

Can I create a derived field using python marshmallow that only available when deserialized?


I have the following marshmallow schema:

class TimeSeriesSchema(Schema):

    timestamp = fields.DateTime(required=True)
    # year = fields.Method("get_year_from_timestamp")
    # year = fields.Function(lambda obj: obj.timestamp.year)
    latitude = fields.Number(allow_none=True)
    longitude = fields.Number(allow_none=True)


    # def get_year_from_timestamp(self, value):
    #     return obj.timestamp.year

Is there a way for me to have year be a field that is only accessible when timeseries is deserialized? The two commented out approaches do not work since they only expose year when serialized.

To illustrate in code, I would like to be able to do the following:

timeseries_data = {
    'timestamp': '2020-12-30T10:00:00',
    'latitude': None, 
    'longitude': None
}
schema = TimeSeriesSchema()
timeseries = schema.load(timeseries_data)

timeseries['year'] = 2020

Solution

  • You can use a post load method to achieve what you want-

    class TimeSeriesSchema(Schema):
    
        timestamp = fields.DateTime(required=True)
        latitude = fields.Number(allow_none=True)
        longitude = fields.Number(allow_none=True)
    
        @post_load
        def add_year(self, data, **kwargs):
            data["year"] = data["timestamp"].year
            return data
    

    This doesn't add any handling for if someone tries to specify "year" in a dump or load, but lets you add derived fields. You could also use this to serialize to a custom Timeseries class with a year property.