Using pydantic
in Python how can I parse data where I want the key of a mapping to be placed into one attribute and the value of a mapping placed into anothe rattribute?
For example, imagine my data is represented as
data = {
"pets": [
{"felix": "cat"},
{"rover": "dog"},
{"snuffles": "dog"},
]
}
And my pydantic models are
from typing import Literal
from pydantic import BaseModel
class Pet(BaseModel):
name: str
species: Literal["dog", "cat"]
class Household(BaseModel):
pets: list[Pet]
Obviously Household(**data)
doesn’t work to parse the data into the class. How can I adjust the class so this does work (efficiently).
Ideally the data would be in this format
data_transformed = {
"pets": [
{"name": "felix", "species": "cat"},
{"name": "rover", "species": "dog"},
{"name": "snuffles", "species": "dog"},
]
}
And this would then work.
Household(**data_transformed)
But if the data is in the original format (data
), how can I write a pydantic class to parse it?
2
Answers
I have solved this by adding a
pydantic.root_validator
to the Pet class like so:Output:
This may be a matter of personal preference, but I think this is best solved by a regular validator on the
Household
model and not by a root validator on thePet
model.This seems to be a rather obscure edge-case, where the data you want to parse as a
Household
has weirdly-formattedpets
. I would still assume that a single instance ofPet
should not expect this format to ever occur, which is why I find it semantically more appropriate to perform this transformation on theHousehold
model.More importantly however, I think a simple
each_item=True
validator makes the intent much clearer and is more readable.