使用Python Marshmallow进行数据类型转换
我试图使用棉花糖模式来序列化python对象。下面是我为数据定义的模式使用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
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()
。