使用Python Marshmallow进行数据类型转换

使用Python Marshmallow进行数据类型转换,python,python-3.x,marshmallow,Python,Python 3.x,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_ac

我试图使用棉花糖模式来序列化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的值被转换为各自的数据类型,但细节保持不变

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}
我需要将输入数据序列化为我在模式中定义的相应数据类型。我有什么做错了吗?有谁能指导我如何用棉花糖来达到这个目的吗

我正在使用

python 3.6
marshmallow 3.5.1
编辑

上述输入数据是从HBase获取的。默认情况下,HBase将其所有值存储为字节,并返回为字节。下面是我从HBase获得的格式

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

然后,我解码这个字典并将其传递给我的UserSchema,将其序列化以用于web API。

您混淆了序列化(转储)和反序列化(加载)

转储从对象形式转变为json可序列化的基本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'}}

正如Jérôme所提到的,您混淆了序列化(转储)和反序列化(加载)。根据您的要求,您应该按照建议使用
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\u process\u details
将字符串类型转换为字典,以便进行正确的反序列化。

感谢您的回复。是的,你是对的,我可以使用load,但我正在尝试将序列化数据返回到web应用程序。我已经编辑了questionUse dump,将带有模式的对象转储到API中。要使用BD数据构建对象,可以使用schema.load,但通常使用数据访问对象或类似ORM的层(如sql alchemy)。如果直接从DB到API,首先就不需要对象。在API中使用
eval
是一个危险信号。永远不要评估外部世界的数据。在DB数据上使用它可能没有那么危险,但它看起来像是一个设计问题。@Jérôme感谢您强调这一点并告知我这个危险信号。我在这里的目的是告诉大家,如果需要字符串类型的输入,请使用
pre_load
。我们可以使用其他方法将字符串转换为dict,比如
json.loads()