How to write a Pydantic model to accept a Dictionary of Dictionaries

Viewed 9729

The code below is modified from the Pydantic documentation I would like to know how to change BarModel and FooBarModel so they accept the input assigned to m1. I have tried using __root__ and syntax such as Dict[str, BarModel] but have been unable to find the magic combination.

from pydantic import BaseModel

class BarModel(BaseModel):
    whatever: float
    foo: str

class FooBarModel(BaseModel):
    banana: str
    bar: BarModel

m = FooBarModel(banana='a', bar={'whatever': 12.3, 'foo':'hello'})
m1 = FooBarModel({
  'a':{'whatever': 12.3, 'foo':'hello'},
  'b':{'whatever': 12.4, 'foo':'bye'}
})

print(m.dict())   # returns a dictionary:
print(m1.dict())  # TypeError

The final solution will be deployed in a FastAPI context.

2 Answers

If all you're trying to do is have a dictionary of BarModel's in another model, this answers your question:

from typing import Dict
from pydantic import BaseModel

class BarModel(BaseModel):
    whatever: float
    foo: str

class FooBarModel(BaseModel):
    dictionaries: Dict[str, BarModel]

m1 = FooBarModel(dictionaries={
    'a': {'whatever': 12.3, 'foo': 'hello'},
    'b': {'whatever': 12.4, 'foo': 'bye'}
}

print(m1.dict())

You already found your magic combination, you haven't realized it yet.

from pydantic import BaseModel
from typing import Dict

class BarModel(BaseModel):
    whatever: float
    foo: str

class FooBarModel(BaseModel):
    banana: str
    bar: Dict[str, BarModel]


m1 = FooBarModel(banana="a", bar={
  'a':{'whatever': 12.3, 'foo':'hello'},
  'b':{'whatever': 12.4, 'foo':'bye'}
})

assert m1.dict() == {'banana': 'a', 'bar': {'a': {'whatever': 12.3, 'foo': 'hello'}, 'b': {'whatever': 12.4, 'foo': 'bye'}}}

This runs without any errors.

Note that we still have banana, if you want to discard it, simply delete.

If you wanted use pure typing and some static analyzer your examples would evaluate to this

from typing import Dict, Union
m = FooBarModel(banana='a', bar={'whatever': 12.3, 'foo':'hello'})


m: Dict[str, Union[str, Dict[str, Union[float, str]]]]

But what you want is actually this

from typing import Dict, Union

m1 = FooBarModel({
  'a':{'whatever': 12.3, 'foo':'hello'},
  'b':{'whatever': 12.4, 'foo':'bye'}
})

m1: Dict[str, Union[str, Dict[str, Dict[str, Union[float, str]]]]]
Related