I am using Fastapi, Celery and Pydantic(2.4). The issue I'm encountering is that when I attempt to create a Model instance (args = Model(**args)
) from a dictionary, the setting
value is not being converted into an instance of the SettingItem
class; instead, it becomes a dict.
How can I make the setting
an instance of SettingItem?
from typing import List
from pydantic import BaseModel
class SettingItem(BaseModel):
setting_id: str
alias: str
date: str
class Model(BaseModel):
id: str
setting: List[SettingItem]
@app.task
def get_data(args: Model):
if isinstance(args,dict)
args = Model.model_construct(**args)
# this line throws an exception. The root cause is that args.setting is a dict instead of an instance of SettingItem
dates = [x.date for x in args.setting]
...
@api.get("/")
def run(args:Model)
get_data.delay(args.model_dumps())
I have tried Model.model_validate_json()
and Model.parse_obj()
,none of them works
Basically, with the following test, you can see the setting
type is SettingItem
:
d = dict(setting=[dict(setting_id='1', alias='a', date='2023')], id="1")
m = Model(**d)
print(type(m.setting[0]))
Out:
__main__.SettingItem
So there's nothing to do with your pydantic
models.
It seems the problem is related to this line get_data.delay(args.model_dumps())
as you converted the Model
to a dict
yourself. Therefore, obviously, you would get a dict
within the get_data()
method not the Model
.
To solve the issue, you would need whether to pass the args
without any conversion or convert it back to Model
within the get_data()
method as follows:
@app.task
def get_data(args: dict):
if isinstance(args, dict)
args = Model.model_validate(args)
...
To ensure it works look at this:
d = dict(setting=[dict(setting_id='1', alias='a', date='2023')], id="1")
m = Model(**d)
dd = m.model_dump() # the thing you have done in run() method
mm = Model.model_validate(dd) # convert it back again from dict to Model
print(type(mm.setting[0]))
Out:
__main__.SettingItem
[NOTE]:
parse_obj()
is being deprecated in pydantic
version 2, so it's better to use model_validate()
instead.