Преобразование типа данных с использованием Python Marshmallow - PullRequest
2 голосов
/ 07 мая 2020

Я пытаюсь использовать схему Marshmallow для сериализации объекта python. Ниже приведена схема, которую я определил для своих данных.

from marshmallow import Schema, fields

class User:

    def __init__(self, name = None, age = None, is_active = None, details = None):
        self.name = name
        self.age = age
        self.is_active = is_active
        self.details = details

class UserSchema(Schema):
    name = fields.Str()
    age = fields.Int()
    is_active = fields.Bool()
    details = fields.Dict()

Ввод будет в формате словаря, а все значения будут в виде строки.

user_data = {"name":"xyz", "age":"20", "is_active": 'true',"details":"{'key1':'val1', 'key2':'val2'}"}

Когда я пытаюсь запустить приведенный ниже фрагмент, значения age и is_active были преобразованы в соответствующий тип данных, но подробности остались без изменений .

user_schema = UserSchema()
user_dump_data = user_schema.dump(user_data)
print(user_dump_data)

Вывод:

{'name': 'xyz', 'is_active': True, 'details': "{'key1':'val1', 'key2':'val2'}", 'age': 20}

Мне нужно сериализовать входные данные в соответствующий тип данных, который я определил в своей схеме. Что я делаю неправильно? Может ли кто-нибудь посоветовать мне, как добиться этого с помощью Marshmallow?

Я использую

python 3.6
marshmallow 3.5.1

Edit

Указанные выше входные данные получены из HBase . По умолчанию HBase хранит все свои значения как байты и возвращает как байты. Ниже представлен формат, который я получил из HBase

{b'name': b'xyz', b'age': b'20', b'is_active': b'true', b'details': b"{'key1':'val1', 'key2':'val2'}"}

Затем я декодирую этот словарь и передаю его в свой UserSchema, чтобы сериализовать его для использования в веб-API.

Ответы [ 2 ]

1 голос
/ 11 мая 2020

Как упоминал Жером, вы путаете сериализацию (сброс) с десериализацией (загрузкой). В соответствии с вашим требованием вы должны использовать Schema.load, как предлагается.

Поскольку все входные значения должны быть строкового типа. Вы можете использовать pre_load для регистрации метода предварительной обработки данных следующим образом:

from marshmallow import Schema, fields, pre_load

class UserSchema(Schema):
    name = fields.Str()
    age = fields.Int()
    is_active = fields.Bool()
    details = fields.Dict()

    @pre_load
    def pre_process_details(self, data, **kwarg):
        data['details'] = eval(data['details'])
        return data

user_data = {"name":"xyz", "age":"20", "is_active": 'true',"details":"{'key1':'val1', 'key2':'val2'}"}

user_schema = UserSchema()
user_loaded_data = user_schema.load(user_data)
print(user_loaded_data)

Здесь pre_process_details преобразует строковый тип в словарь для правильной десериализации.

1 голос
/ 11 мая 2020

Вы путаете сериализацию (сброс) и десериализацию (загрузку).

Дамп происходит из формы объекта в json -сериализуемые базовые типы c python (с использованием Schema.dump) или json строка (используя Schema.dumps). Загрузка - это обратная операция.

Обычно ваш API загружает (и проверяет) данные из внешнего мира и выгружает (без проверки) ваши объекты во внешний мир.

Если ваши входные данные эти данные, и вы хотите загрузить их в объекты, вам нужно использовать load, а не dump.

user_data = {"name":"xyz", "age":"20", "is_active": 'true',"details":"{'key1':'val1', 'key2':'val2'}"}
user_loaded_data = user_schema.load(user_data)
user = User(**user_loaded_data)

За исключением случаев, когда вы это сделаете, вы столкнетесь с другой проблемой. DictField ожидает данные как dict, а не str. Вам нужно ввести

user_data = {"name":"xyz", "age":"20", "is_active": 'true',"details": {'key1':'val1', 'key2':'val2'}}
...