You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 08:52:48