Marshmallow加载异常求助:Unknown field错误及嵌套数据无法读取问题
解决Marshmallow加载时的Unknown Field错误与嵌套数据读取问题
让我们一步步拆解你的问题,找到根本原因和解决方案:
一、先搞定「Unknown field」验证错误
这个错误的核心原因很明确:你用了单个用户的PersonSchema去加载一个包含多个用户的字典。
你的users变量是类似这样的结构:
{ "sherlock": {"full_name": "...", ...}, "doll": {"full_name": "...", ...} }
而PersonSchema的设计是用来解析单个用户的数据(比如users["sherlock"]这种结构),当你把整个多用户字典传给它时,Marshmallow会把sherlock、doll这些用户名当作「字段名」,但你的Schema里根本没定义这些字段,所以就抛出了「Unknown field」错误。
解决方案分两种场景:
场景1:只需要加载单个用户数据
直接传入单个用户的字典即可:
# 比如加载sherlock的信息 serialized_data = serializer_inst.load(users["sherlock"])
场景2:需要加载整个多用户字典
你需要定义一个能处理这种字典结构的Schema,用Dict字段嵌套PersonSchema:
from marshmallow import fields, Schema class UsersSchema(Schema): # 用__root__字段直接接收顶级的用户字典 __root__ = fields.Dict( keys=fields.Str(), # 用户名是字符串类型 values=fields.Nested(PersonSchema) # 每个值是单个用户的结构 ) # 使用示例 try: serialized_data = UsersSchema().load(users) print(serialized_data) except ValidationError as err: print(err)
二、实现嵌套地址信息的读取
你的原始数据里地址是平级的address_street、address_city、address_country字段,要把它们转成嵌套的address对象,需要做两步:
1. 定义地址的嵌套Schema
class AddressSchema(Schema): street = fields.Str() city = fields.Str() country = fields.Str()
2. 修改PersonSchema,添加嵌套字段并转换数据
用Marshmallow的pre_load钩子,在数据验证前把平级的地址字段合并成嵌套结构:
from marshmallow import fields, Schema, pre_load class PersonSchema(Schema): full_name = fields.Str() email = fields.Email() age = fields.Integer() address = fields.Nested(AddressSchema) # 嵌套的地址字段 phone_number = fields.Str() @pre_load def flatten_address(self, data, **kwargs): # 从原始数据中提取平级的地址字段,合并成address字典 address_data = { "street": data.pop("address_street", None), "city": data.pop("address_city", None), "country": data.pop("address_country", None) } # 过滤掉空值(可选,避免生成空字段) address_data = {k: v for k, v in address_data.items() if v is not None} # 把合并后的address放回数据中 data["address"] = address_data return data
三、完整代码示例
把两部分结合起来,完整的可运行代码如下:
from marshmallow import fields, Schema, ValidationError, pre_load class AddressSchema(Schema): street = fields.Str() city = fields.Str() country = fields.Str() class PersonSchema(Schema): full_name = fields.Str() email = fields.Email() age = fields.Integer() address = fields.Nested(AddressSchema) phone_number = fields.Str() @pre_load def flatten_address(self, data, **kwargs): address_data = { "street": data.pop("address_street", None), "city": data.pop("address_city", None), "country": data.pop("address_country", None) } address_data = {k: v for k, v in address_data.items() if v is not None} data["address"] = address_data return data class UsersSchema(Schema): __root__ = fields.Dict(keys=fields.Str(), values=fields.Nested(PersonSchema)) # 模拟你的原始数据 users = { "sherlock": { "full_name": "Sherlock Holmes", "email": "sherlock@example.com", "age": 35, "address_street": "221B Baker St", "address_city": "London", "address_country": "UK", "phone_number": "123456789" }, "doll": { "full_name": "Irene Adler", "email": "irene@example.com", "age": 32, "address_street": "Unknown", "address_city": "London", "address_country": "UK", "phone_number": "987654321" } } # 加载数据 try: serialized_data = UsersSchema().load(users) print(serialized_data) except ValidationError as err: print(err)
运行后,你会得到包含嵌套地址结构的多用户数据,同时不会再出现Unknown field错误。
内容的提问来源于stack exchange,提问作者Hermine
相关产品推荐
相关产品推荐

