首页 > 解决方案 > 滤锅:如何处理嵌套模式的空值

问题描述

使用滤锅 1.5.1,如果我传递null给由嵌套模式定义的属性:

class ChildSchema(colander.Schema):
    a = colander.SchemaNode(colander.Integer(), missing=None)
    b = colander.SchemaNode(colander.Integer(), missing=None)

class ParentSchema(colander.Schema):
    c = colander.SchemaNode(colander.Integer(), missing=None)
    d = ChildSchema(missing=None)
example json:
{
    "c": 1,
    "d": null
}

然后在反序列化时出现此错误:

"\"None\" is not a mapping type: Does not implement dict-like functionality."

未按d预期传递属性函数,并反序列化为None. 如何正确处理反序列化null传递给嵌套模式的值?None根据文档, 我希望行为能够返回。反序列化组合

标签: python-3.5colander

解决方案


请考虑以下几点:

您需要以下导入。

import colander
from colander import SchemaType, Invalid, null

以下与您的子架构相同。

class ChildSchema(colander.Schema):
    a = colander.Schema(colander.Integer(), missing=None)
    b = colander.Schema(colander.Integer(), missing=None)

下面是所有魔法发生的地方。我们创建自己的类型。请注意,它可能缺少滤锅 SchemaTypes 中的内置函数可能提供的一些基本功能(如序列化)。如果接收到的对象为 null 或 None ,则返回它而不进行任何更改。如果它不是 null 或 None 并且不是字典,它将引发错误,如果它是字典,它将使用您的 ParentSchema 序列化,即使 Parent 的属性为 null 或 None ({"d": null} )。

class MyType(SchemaType):
    def deserialize(self, node, cstruct):
        if cstruct is null:
            return null
        if cstruct is None:
            return None
        if not isinstance(cstruct, dict):
            raise Invalid(node, '%r is not an object' % cstruct)
        else:
            return ChildSchema().deserialize(cstruct)

我们使用魔法类型创建父模式:

class ParentSchema(colander.Schema):
    c = colander.SchemaNode(colander.Integer(), missing=None)
    d = colander.SchemaNode(MyType(), missing=None)

“d”将按照您的意愿反序列化。现在让我们看一些它的用法示例:

schema = ParentSchema()

示例 1.“d”为空(主要问题)

schema.deserialize({"c": 1, "d": null})

输出 1

{"c": 1, "d": None}

示例 2.“d”为无

schema.deserialize({"c": 1, "d": None})

输出 2

{"c": 1, "d": None}

示例 3. 正常行为

schema.deserialize({'c': 1, 'd': {'a': 1}})

输出 3。

{'c': 1, 'd': {'a': 1, 'b': None}}

示例 5. 错误 "d" 不是 dict

 schema.deserialize({'c': 1, 'd': [] })

输出 5

 # Invalid: {'d': '[] is not an object'}

示例 6. 错误验证器不是数字

 schema.deserialize({'c': 1, 'd': {'a': "foobar"}})

输出 6

# Invalid: {'a': u'"foobar" is not a number'}

为了写这个答案,我使用了https://docs.pylonsproject.org/projects/colander/en/latest/extending.html作为来源。


推荐阅读