【问题标题】:How Pydantic handles unknown dictionary keysPydantic 如何处理未知的字典键
【发布时间】:2021-12-11 17:17:18
【问题描述】:

我有一个想要使用 Pydantic 验证的 json 对象。

我面临的问题是:

1 - 我不知道 JSON 中有多少字段。下面的示例有 2 个键\字段:“225_5_99_0”和“225_5_99_1”

2 - 在这种情况下,我不知道字段的名称:它可以是“225_5_99_0”或“226_0_0_0”。我只知道他们遵守一些约定。

3 - 某些字段的关键字对于模型的字段名称无效,例如“*”键。我可以通过将字段名称别名为“星号”来克服这一点。

关于处理这种 JSON 的最佳方法有什么想法吗?

{
    "225_5_99_0": {
        "*": {
            "flag": "",
            "group1": "225.5.99.0",
            "group_type": "M",
            "uptime": "0:11:23",
            "iif": {"lo5": {
                "flag": "R",
                "uptime": "0:44:41"
            }
            },
            "oil": {
                "bun_1215": {
                    "flag": "",
                    "join_time": "00:03:14",
                    "uptime": "0:42:27"
                },
                "bun_1218": {
                    "flag": "",
                    "join_time": "00:02:44",
                    "uptime": "0:44:41"
                }
            },
            "address": "100.100.100.100",
            "rp": "*",
            "source": "*",
            "upstream": "Joined(00:00:19)"
        }
    },
    "225_5_99_1": {
        "*": {
            "flag": "",
            "group1": "225.5.99.0",
            "group_type": "M",
            "uptime": "0:11:23",
            "iif": {"lo5": {
                "flag": "R",
                "uptime": "0:44:41"
            }
            },
            "oil": {
                "bun_1215": {
                    "flag": "",
                    "join_time": "00:03:14",
                    "uptime": "0:42:27"
                },
                "bun_1218": {
                    "flag": "",
                    "join_time": "00:02:44",
                    "uptime": "0:44:41"
                }
            },
            "address": "100.100.100.100",
            "rp": "*",
            "source": "*",
            "upstream": "Joined(00:00:19)"
        }
    },        
  }
}

【问题讨论】:

  • 可以提供更多信息:您究竟想验证什么?如果您可以发布一些有用的模型草案。一般来说,pydantic 是一个 parsing 库,而不是一个验证库:这里的区别可能并不重要,但是您想将其视为为您提供了有效的 models (和如果不能,则放弃)而不是验证其​​输入。因此,了解您希望模型看起来像什么会有所帮助...
  • 谢谢@alex_noname - 我使用了你对链接问题的回复。

标签: python json pydantic


【解决方案1】:

感谢@alex_noname 的reply,我得到了我需要的东西。我在最后附上了完整的代码和打印输出。

继续我的问题中的部分:

1 - 我不知道 JSON 中有多少字段。下面的示例有 2 个键\字段:“225_5_99_0”和“225_5_99_1”

Example 类必须将 root 属性定义为字典,因此它成为嵌套对象的字典。

您还必须实现 itergetitem 以使 Example 类的行为类似于现在的 dict\list。

另见:Custom Root Types


2 - 在这种情况下,我不知道字段的名称:它可以是“225_5_99_0”或“226_0_0_0”。我只知道他们遵守一些约定。

我定义了:

UnderScoreNumbers = constr(regex=r'^[0-9_]*$')
...
__root__: Dict[UnderScoreNumbers, Dict]

所以键现在被验证为由数字和下划线组成的字符串,例如225_5_99_0等


3 - 某些字段的关键字对模型的字段名称无效,例如“*”键。我可以通过将字段名称别名为“星号”来克服这一点。

我定义了一个别名为 '' 的字段来使用 dict 的键 '',它在 json 中是唯一的。 我认为,如果您可以影响生成 json 的开发人员,建议避免使用不能是有效属性名称的字段,例如'*'、'123a'等

asterisk: Dict[str, Dict] = Field(alias='*')


from typing import Dict

from pydantic import BaseModel, constr

example_dict = {
    "225_5_99_0": {
        "*": {
            "flag": "",
            "group1": "225.5.99.0",
            "group_type": "M",
            "uptime": "0:11:23",
            "iif": {"lo5": {
                "flag": "R",
                "uptime": "0:44:41"
            }
            },
            "oil": {
                "bun_1215": {
                    "flag": "",
                    "join_time": "00:03:14",
                    "uptime": "0:42:27"
                },
                "bun_1218": {
                    "flag": "",
                    "join_time": "00:02:44",
                    "uptime": "0:44:41"
                }
            },
            "address": "100.100.100.100",
            "rp": "*",
            "source": "*",
            "upstream": "Joined(00:00:19)"
        }
    },
    "225_5_99_1": {
        "*": {
            "flag": "",
            "group1": "225.5.99.0",
            "group_type": "M",
            "uptime": "0:11:23",
            "iif": {"lo5": {
                "flag": "R",
                "uptime": "0:44:41"
            }
            },
            "oil": {
                "bun_1215": {
                    "flag": "",
                    "join_time": "00:03:14",
                    "uptime": "0:42:27"
                },
                "bun_1218": {
                    "flag": "",
                    "join_time": "00:02:44",
                    "uptime": "0:44:41"
                }
            },
            "address": "100.100.100.100",
            "rp": "*",
            "source": "*",
            "upstream": "Joined(00:00:19)"
        }
    },        
  }
}

class Asterisk(BaseModel):
    asterisk: Dict[str, Dict] = Field(alias='*')

UnderScoreNumbers = constr(regex=r'^[0-9_]*$')


class Example(BaseModel):
    __root__: Dict[UnderScoreNumbers, Dict]

    def __iter__(self):
        return iter(self.__root__)

    def __getitem__(self, item):
        return self.__root__[item]


if __name__ == '__main__':
    e1 = Example.parse_obj(example_dict)
    for key in e1:
        print(f'{key}: {e1[key]}')
    print(e1)
    print('The End!')

输出:

225_5_99_0: {'*': {'flags': '', ...
225_5_99_1: {'*': ...
__root__={'225_5_99_0': {'*': {'flags': '', ....

【讨论】:

    猜你喜欢
    • 2021-11-10
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多