tortoise / tortoise/tortoise-orm
Initializer doesn't support multiple apps
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
Describe the bug
Initalizer only supports one app label in the arguments to passed to it. In trying to run it multiple times it fails at the first app giving an error for the other apps.
raise ConfigurationError(
tortoise.exceptions.ConfigurationError: default_connection for the model <class 'app2.models.Category'> cannot be None
This makes it difficult to test when there are multiple apps.
To Reproduce
app1/models.py:
from tortoise.models import Model
from tortoise import fields
class Users(Model):
id = fields.IntField(pk=True)
password = fields.CharField(max_length=128, blank=True, null=True)
email = fields.CharField(max_length=120, unique=True, index=True)
app2/models.py:
from tortoise.models import Model
from tortoise import fields
class Category(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=128)
user = fields.ForeignKeyField('app1.Users')
main.py:
import asyncio
import os
from tortoise import Tortoise
from tortoise.contrib.test import finalizer, initializer
db_url = "sqlite://:memory:?cache=shared"
def setup_db():
Tortoise.init_models(["app1.models"], "app1")
Tortoise.init_models(["app2.models"], "app2")
print('Initializing app1')
initializer(['app1.models'], db_url=db_url, app_label="app1")
print('Initializing app2')
initializer(['app2.models'], db_url=db_url, app_label="app2")
print('DB initialized')
finalizer()
print('finalized')
try:
setup_db()
print('setup_db done')
finally:
asyncio.run(Tortoise.close_connections())
At the line where app1 is run through initializer the following error is given:
raise ConfigurationError(tortoise.exceptions.ConfigurationError: default_connection for the model <class 'app2.models.Category'> cannot be None
The following also fails with the same error. Here both apps models.py are provided as modules, but there is still the restriction of only one app label.
def setup_db():
Tortoise.init_models(["app1.models"], "app1")
Tortoise.init_models(["app2.models"], "app2")
initializer(['app1.models', 'app2.models'], db_url=db_url, app_label="app1")
print('DB initialized')
finalizer()
print('finalized')
tortoise.exceptions.ConfigurationError: default_connection for the model <class 'app2.models.Category'> cannot be Non
Expected behavior
There should be a a way to run multiple apps through the initializer
Additional context (Possible Fix)
Changing initalizer to accept Dict[str, Iterable[Union[str, ModuleType]]], a dictionary of app_labels and models (same as the FastAPI register_tortoise CONFIG argument or how Aerich accepts apps and models config) fixes the issue.
The way it's done here is just a demonstration and would not be backward compatibile (but it would be easy to make it so, by using a separate argument to pass through multiple apps, same as register_tortoise has both config and modules arguments).
Changes to tortoise/contrib/test/__init__.py:
from typing import Dict
def getDBConfig(app_label: str, modules: Dict[str, Iterable[Union[str, ModuleType]]]) -> dict:
"""
DB Config factory, for use in testing.
:param app_label: Label of the app (must be distinct for multiple apps).
:param modules: List of modules to look for models in.
"""
return _generate_config(
_TORTOISE_TEST_DB,
app_modules=modules,
testing=True,
connection_label=app_label,
)
def initializer(
modules: Dict[str, Iterable[Union[str, ModuleType]]],
db_url: Optional[str] = None,
app_label: str = "models",
loop: Optional[AbstractEventLoop] = None,
) -> None:
....# Rest of function
The setup_db function in main.py above would then be:
def setup_db():
Tortoise.init_models(["app1.models"], "app1")
Tortoise.init_models(["app2.models"], "app2")
initializer({'app1': ['app1.models'], 'app2': ["app2.models"]}, db_url=db_url, app_label="default")
print('DB initialized')
finalizer()
print('finalized')
I can make PR if you think I'm on the right track with this, unless I'm missing something about the current behaviour. Multiple apps are needed to be initialized in this way when there are foreign keys from one app model to another.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in tortoise/contrib/test/init.py by reading initializer and getDBConfig, then run the provided main.py reproduction with models from app1 and app2. Confirm that initialization supports multiple app labels and cross-app foreign keys without the default_connection error, while checking the existing single-app behavior for compatibility.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlite
- Domain
- database, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100