Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON serialization using Marshmallow - skip None attributes

I am using Marshmallow to send instance of my Decision class to JSON. However, this will also dump the attributes which are None, e.g. my attribute score will translate to null in JSON. After that I am unable to read the JSON again using the same approach.

https://repl.it/repls/VoluminousMulticoloredFacts

The last line is where it currently fails. I need to either NOT dump None to JSON or skip null during loading:

import json
from marshmallow import Schema, fields, post_load

json_data = """{
    "appid": "2309wfjwef",
    "strategy": "First Strategy"
}"""

# Output class definition
class Decision(object):
    def __init__(self, appid = None, strategy = None, score = None):
        self.appid = appid
        self.strategy = strategy
        self.score = score

class DecisionSchema(Schema):
    appid = fields.Str()
    strategy = fields.Str()
    score = fields.Int()

    @post_load
    def make_decision(self, data):
        return Decision(**data)

# Deserialization into object
dec_json = json.loads(json_data)
schema = DecisionSchema()
dec = schema.load(dec_json).data

print(dec.strategy)

# Dump results back to JSON
schema = DecisionSchema()
out = schema.dumps(dec)

print(out.data)

# Load back from dump
schema = DecisionSchema()
dec = schema.load(out).data

#print(dec.strategy) # returns error currently
like image 627
Tomas Greif Avatar asked Aug 29 '26 22:08

Tomas Greif


2 Answers

An "official" answer from marshmallow development team can be found in this comment in the bugtracker:

Use a post_dump method.

from marshmallow import Schema, fields, post_dump

class BaseSchema(Schema):
    SKIP_VALUES = set([None])

    @post_dump
    def remove_skip_values(self, data, **kwargs):
        return {
            key: value for key, value in data.items()
            if value not in self.SKIP_VALUES
        }


class MySchema(BaseSchema):
    foo = fields.Field()
    bar = fields.Field()


sch = MySchema()
sch.dump({'foo': 42, 'bar': None}).data  # {'foo': 42}

As I point out in a further comment, there's a shortcoming: it will also remove None when the field's allow_none is True.

like image 92
Jérôme Avatar answered Sep 01 '26 14:09

Jérôme


As I pointed out in my comment above this messes with the order if you use the

class Meta:
    fields = (
        'field1', 'field2'
    )
    ordered = True

To fix this I used this:

# Remove None fields
@pre_dump
def remove_skip_values(self, data):
    return {
        key: value for key, value in data.items()
        if value is not None
    }

This works for my dictonary of objects

like image 34
Kristofer Källsbo Avatar answered Sep 01 '26 14:09

Kristofer Källsbo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!