#json #python-3.x #serialization #marshmallow
#json #python-3.x #сериализация #marshmallow
Вопрос:
Я использую Marshmallow для отправки экземпляра моего класса Decision в JSON. Однако при этом также будут удалены атрибуты, которые являются None
, например, мой атрибут score
будет переведен в null
в JSON. После этого я не могу снова прочитать JSON, используя тот же подход.
https://repl.it/repls/VoluminousMulticoloredFacts
Последняя строка — это то место, где в данный момент происходит сбой. Мне нужно либо НЕ выполнять сброс None
в JSON, либо пропускать null
во время загрузки:
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
Ответ №1:
«Официальный» ответ от команды разработчиков marshmallow можно найти в этом комментарии к bugtracker:
Используйте post_dump
метод.
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}
Как я указываю в дальнейшем комментарии, есть недостаток: он также будет удален, None
когда поле allow_none
равно True
.
Комментарии:
1. Еще одна проблема заключается в том, что это нарушит порядок ваших полей, если вы используете ordered = True
2. Конечно. Метод может быть изменен, чтобы сохранить порядок и вернуть
OrderedDict
.3. Неплохо. Поскольку version
post_load
всегда передает аргументmany
, поэтому метод должен выглядеть следующим образомdef remove_skip_values(self, data, many):
4. Да, начиная с marshmallow 3, оформленные методы должны принимать ** kwargs.
Ответ №2:
Как я указал в своем комментарии выше, это нарушает порядок, если вы используете
class Meta:
fields = (
'field1', 'field2'
)
ordered = True
Чтобы исправить это, я использовал это:
# 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
}
Это работает для моего справочника объектов
Комментарии:
1. Это более надежный выбор! Для меня должно быть принято!
2. можем ли мы сделать это необязательным с помощью начального параметра
remove_none
, например MySchema(remove_none= True).dump(obj)?3. Я получаю сообщение об ошибке:
remove_skip_values() got an unexpected keyword argument 'many'
4. @chrisinmtown: Я получил то же самое. Я исправил это, добавив
**kwargs
в список параметров дляremove_skip_values
. Кроме того, я обнаружил, что использование@pre_dump
конфликтовало с имеющимся у меня хуком post_load, который преобразует данные в экземпляр класса. Переключение на@post_dump
исправило это.