简体   繁体   中英

How Pydantic handles unknown dictionary keys

I have a json object that I want to validate using Pydantic.

The problem I am facing is that:

1 - I don't know how many fields I will have in the JSON. The example below has 2 keys\\fields: "225_5_99_0" and "225_5_99_1"

2 - I don't know the names of the fields in this case: It can be "225_5_99_0" or "226_0_0_0". I only know that they adhere to some convention.

3 - Some of the fields have keywords that are not valid for the model's field names, like the '*' key. This I might overcome by aliasing the field name to "asterisk".

Any ideas on the best way to tackle such a 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)"
        }
    },        
  }
}

Thanks to @alex_noname 's reply , I got what I needed. I've attached the full code and printout at the end.

To follow on the sections in my question:

1 - I don't know how many fields I will have in the JSON. The example below has 2 keys\\fields: "225_5_99_0" and "225_5_99_1"

The class Example must define the root attribute as a dictionary, so it becomes a dictionary of the nested objects.

You must also implement the iter and getitem to make Example class behave like a dict\\list that it is now.

Also see: Custom Root Types


2 - I don't know the names of the fields in this case: It can be "225_5_99_0" or "226_0_0_0". I only know that they adhere to some convention.

I defined:

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

so the keys are now validated as a string consisting of numbers and underscores, eg 225_5_99_0 etc.


3 - Some of the fields have keywords that are not valid for the model's field names, like the '*' key. This I might overcome by aliasing the field name to "asterisk".

I defined a field with an alias ' ' to consume the dict's key ' ' which is unique in the json. I think that if you can influence the developers that generate the json, suggest avoiding fields that can't be valid attribute names, eg '*', '123a', etc.

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!')

Output:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM