7

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.

snow6oy
  • 678
  • 1
  • 7
  • 16
  • Have got the above working using __root__={} syntax but still unable to apply it to FastAPI. This bug looks relevant https://github.com/tiangolo/fastapi/issues/911 – snow6oy Mar 07 '21 at 13:15

2 Answers2

9

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())
Jason Rebelo Neves
  • 1,131
  • 10
  • 20
  • This is working for me. Also I realised that with __root__ my original data can be passed in without the keyword argument. There is still an issue to do with how BarModel is exported in FastAPI, but I am slowly unravelling the pieces. Thanks again. – snow6oy Mar 07 '21 at 17:24
4

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]]]]]
Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85