I am trying to structure the code for my data model using pydantic
but I am running into an apparently insolvable problem.
The code below works as expected:
main.py
#
from __future__ import annotations
#
from pydantic import BaseModel
#
class Item(BaseModel):
tag: Tag = None
class Config:
orm_mode = True
class Tag(BaseModel):
item: Item = None
class Config:
orm_mode = True
Item.update_forward_refs()
Tag.update_forward_refs()
i = Item()
t = Tag()
i.tag = t
t.item = i
# print(i) fails due to cyclic model but this is another story
Then I am trying to refactor my code like this:
main.py
model/item.py
model/tag.py
with
main.py:
#
from model.item import Item
from model.tag import Tag
#
Item.update_forward_refs()
Tag.update_forward_refs()
#
i = Item()
t = Tag()
#
i.tag = t
t.item = i
model/item.py:
#
from __future__ import annotations
#
from pydantic import BaseModel
#
from .tag import Tag
#
class Item(BaseModel):
tag: Tag = None
class Config:
orm_mode = True
model/tag.py:
#
from __future__ import annotations
#
from pydantic import BaseModel
#
from .item import Item
#
class Tag(BaseModel):
item: Item = None
class Config:
orm_mode = True
This code fails on import because of the cross reference of tag to item and vice versa. But if I remove the imports from the model files:
from .item import Item
from .tag import Tag
The code fails again complaining about missing Tag or Item:
NameError: name 'Tag' is not defined
NameError: name 'Item' is not defined
All other attempts failed, like using explicit reference model.Item
instead of Item
.
What is the correct way to get around this, preferably keeping the nice symmetry of the code ?
Just to share an alternative option - convtools models ( docs | github ), which is pretty young, but it handles cycles:
from typing import Optional
from convtools.contrib.models import DictModel, build
class Item(DictModel):
tag: Optional["Tag"] = None
class Tag(DictModel):
item: Optional[Item] = None
item_data = {"tag": None}
tag_data = {"item": item_data}
item_data["tag"] = tag_data
obj, errors = build(Item, item_data)
"""
>>> In [2]: obj
>>> Out[2]: Item(tag=Tag(item=<convtools.contrib.models.type_handlers.ProxyItem object at 0x103428a60>))
>>>
>>> In [3]: obj.tag
>>> Out[3]: Tag(item=<convtools.contrib.models.type_handlers.ProxyItem object at 0x103428a60>)
>>>
>>> In [4]: obj.tag.item
>>> Out[4]: <convtools.contrib.models.type_handlers.ProxyItem object at 0x103428a60>
>>>
>>> In [5]: obj.tag.item.tag
>>> Out[5]: Tag(item=<convtools.contrib.models.type_handlers.ProxyItem object at 0x103428a60>)
"""
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.