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

如何用Marshmallow指定rec_biblio中activity.category始终为数组?

解决方案:Marshmallow 保留Dict结构同时验证嵌套字段

你可以通过两种方式实现需求:既保持rec_biblio为字典结构,又强制rec_biblio.activity.category为数组类型。

方法一:使用嵌套Schema验证指定字段

这种方式符合Marshmallow的原生设计,通过定义小型嵌套Schema约束特定字段,其余字段保留字典的灵活性。

from marshmallow import Schema, fields

# 定义activity字段的验证Schema
class ActivitySchema(Schema):
    id = fields.Str()  # 可选:如果需要验证id字段可保留,否则删除
    category = fields.List(fields.Str(), required=True)  # 强制为字符串数组,required参数可选

# 主Schema
class BiblioMetadataSchema(Schema):
    """Schema for the biblio metadata."""
    rec_biblio = fields.Nested(Schema.from_dict({
        "activity": fields.Nested(ActivitySchema),
        # 用"*"匹配所有未明确指定的字段,保留原始结构
        "*": fields.Raw()
    }))

说明

  • Schema.from_dict用于动态创建Schema,"*"通配符匹配所有未定义的字段,fields.Raw()确保这些字段保留原始数据类型。
  • ActivitySchema专门约束activity下的category字段,确保它是字符串数组,不影响其他字段的结构。

方法二:使用pre_load钩子做验证与转换

如果只需要处理category字段,钩子函数更灵活,还能自动将单个值转换为数组(适配Elasticsearch可能返回的非数组场景)。

from marshmallow import Schema, fields, ValidationError

class BiblioMetadataSchema(Schema):
    """Schema for the biblio metadata."""
    rec_biblio = fields.Dict()

    @pre_load
    def ensure_category_is_list(self, data, **kwargs):
        rec_biblio = data.get("rec_biblio", {})
        activity = rec_biblio.get("activity", {})
        category = activity.get("category")

        if category is not None:
            # 若category不是数组,尝试转换为数组
            if not isinstance(category, list):
                if isinstance(category, (str, int, float)):
                    activity["category"] = [category]
                else:
                    raise ValidationError("category必须是数组或可转换为数组的单个值")
            # 验证数组元素类型为字符串
            for item in category:
                if not isinstance(item, str):
                    raise ValidationError("category数组中的每个元素必须是字符串")
        
        return data

说明

  • pre_load钩子在数据被Schema加载前执行,可在这里修改或验证数据。
  • 代码包含自动转换逻辑:如果category是单个字符串/数字,会自动转为数组;如果是其他非数组类型,直接抛出验证错误。

使用示例

# 验证合法数据
valid_data = {
    "rec_biblio": {
        "_id": "952822",
        "_legislation": "456/2012",
        "_lib_id": "1",
        "_updated": "2000-01-01T00:00:00.0000000Z",
        "_version": "21007",
        "activity": {
            "id": "74154",
            "category": ["AFS", "DUT"]
        }
    }
}

schema = BiblioMetadataSchema()
result = schema.load(valid_data)
print(result)  # 验证通过,输出原始数据

# 测试单个值转数组
single_category_data = {
    "rec_biblio": {
        "activity": {
            "category": "AFS"
        }
    }
}
result = schema.load(single_category_data)
print(result["rec_biblio"]["activity"]["category"])  # 输出: ["AFS"]

# 测试非法数据
invalid_data = {
    "rec_biblio": {
        "activity": {
            "category": {"foo": "bar"}
        }
    }
}
try:
    schema.load(invalid_data)
except ValidationError as err:
    print(err.messages)  # 输出错误提示

内容的提问来源于stack exchange,提问作者Peter Válek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:27:24