I was making a sample Fast Api server with Tortoise ORM as an asynchronous orm library, but I just cannot seem to return the relations I have defined. These are my relations:
# Category
from tortoise.fields.data import DatetimeField
from tortoise.models import Model
from tortoise.fields import UUIDField, CharField
from tortoise.fields.relational import ManyToManyField
from tortoise.contrib.pydantic import pydantic_model_creator
class Category(Model):
id = UUIDField(pk=True)
name = CharField(max_length=255)
description = CharField(max_length=255)
keywords = ManyToManyField(
"models.Keyword", related_name="categories", through="category_keywords"
)
created_on = DatetimeField(auto_now_add=True)
updated_on = DatetimeField(auto_now=True)
Category_dto = pydantic_model_creator(Category, name="Category", allow_cycles = True)
# Keyword
from models.expense import Expense
from models.category import Category
from tortoise.fields.data import DatetimeField
from tortoise.fields.relational import ManyToManyRelation
from tortoise.models import Model
from tortoise.fields import UUIDField, CharField
from tortoise.contrib.pydantic import pydantic_model_creator
class Keyword(Model):
id = UUIDField(pk=True)
name = CharField(max_length=255)
description = CharField(max_length=255)
categories: ManyToManyRelation[Category]
expenses: ManyToManyRelation[Expense]
created_on = DatetimeField(auto_now_add=True)
updated_on = DatetimeField(auto_now=True)
class Meta:
table="keyword"
Keyword_dto = pydantic_model_creator(Keyword)
The tables have been created correctly. When adding keywords to categories the db state is all good. The problem is when i want to query the categories and include the keywords. I have this code for that:
class CategoryRepository():
@staticmethod
async def get_one(id: str) -> Category:
category_orm = await Category.get_or_none(id=id).prefetch_related('keywords')
if (category_orm is None):
raise NotFoundHTTP('Category')
return category_orm
Debugging the category_orm here I have the following:
category_orm debug at run-time
Which kind of tells me that they are loaded. Then when i cant a Pydantic model I have this code
class CategoryUseCases():
@staticmethod
async def get_one(id: str) -> Category_dto:
category_orm = await CategoryRepository.get_one(id)
category = await Category_dto.from_tortoise_orm(category_orm)
return category
and debugging this, there is no keywords
field
category (pydantic) debug at run-time
Looking at the source code of tortoise orm for the function from_tortoise_orm
@classmethod
async def from_tortoise_orm(cls, obj: "Model") -> "PydanticModel":
"""
Returns a serializable pydantic model instance built from the provided model instance.
.. note::
This will prefetch all the relations automatically. It is probably what you want.
But my relation is just not returned. Anyone have a similar experience ?
The issue occurs when one try to generate pydantic models before Tortoise ORM is initialised. If you look at basic pydantic example you will see that all pydantic_model_creator
are called after Tortoise.init
.
The obvious solution is to create pydantic models after Tortoise initialisation, like so:
await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})
await Tortoise.generate_schemas()
Event_Pydantic = pydantic_model_creator(Event)
Or a more convenient way, use early model init by means of Tortoise.init_models()
. Like so:
from tortoise import Tortoise
Tortoise.init_models(["__main__"], "models")
Tournament_Pydantic = pydantic_model_creator(Tournament)
In the case, the main idea is to split pydantic and db models into different modules, so that importing the first does not lead to the creation of the second ahead of time. And ensure calling Tortoise.init_models()
before creating pydantic models.
A more detailed description with examples can be found here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With