tortoise / tortoise/tortoise-orm

why will "Tortoise.init_models" raise a ConfigurationError

Open
#1,402 4 comments 0 reactions 0 assignees View on GitHub

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
i'm a beginner for fastapi, i have a model that has a ForeignKeyRelation; i want to show this related field with "pydantic_model_creator" function; I learned that it is possible to set "Tortoise.init_models"; but i have a problem with it;

To Reproduce
Here is my application structure.
`

  • ├── app
  • │ ├── api
  • │ │ ├── access_admin.py
  • │ │ ├── Base.py
  • │ │ ├── login.py
  • │ │ ├── role_admin.py
  • │ │ ├── test_auth.py
  • │ │ ├── test_redis.py
  • │ │ └── user.py
  • │ ├── core
  • │ │ ├── Auth.py
  • │ │ ├── Events.py
  • │ │ ├── Exception.py
  • │ │ ├── Helper.py
  • │ │ ├── Middleware.py
  • │ │ ├── Response.py
  • │ │ └── Router.py
  • │ ├── curd
  • │ │ └── user.py
  • │ ├── database
  • │ │ ├── mysql.py
  • │ │ ├── redis.py
  • │ │ └── sqlite.py
  • │ ├── models
  • │ │ ├── base.py
  • │ │ └── serializers.py
  • │ ├── schemas
  • │ │ ├── access.py
  • │ │ ├── base.py
  • │ │ ├── role.py
  • │ │ └── user.py
  • │ └── views
  • │ ├── Base.py
  • │ ├── home.py
  • ├── config.py
  • ├── main.py

`

database connection is setup in app/database/mysql.py:

`
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
import os
from tortoise import Tortoise

DB_ORM_CONFIG = {
"connections" :{
"english_notes":{
'engine': 'tortoise.backends.mysql',
"credentials": {
'host': os.getenv('BASE_HOST', '127.0.0.1'),
'user': os.getenv('BASE_USER', 'notes'),
'password': os.getenv('BASE_PASSWORD', '961025.'),
'port': int(os.getenv('BASE_PORT', 3306)),
'database': os.getenv('BASE_DB', 'english_notes'),
}
}
},

"apps":{
    "english_notes":{"models": ["app.models.base", "aerich.models"], "default_connection": "english_notes"},
    "base" : {"models": ["app.models.base"], "default_connection": "english_notes"},
},

'use_tz': False,
'timezone': 'Asia/Shanghai'
}

async def register_mysql(app: FastAPI):
register_tortoise(
app,
config=DB_ORM_CONFIG,

    generate_schemas=False,
    add_exception_handlers=True,  
)

model is in app/models/base.py:
from tortoise.models import Model
from tortoise import fields

class EnglishSentence(Model):
id = fields.IntField(pk=True)
original = fields.CharField(max_length=255, description="英语原文", unique=True)
translation = fields.CharField(max_length=255, description="中文翻译")
notes = fields.TextField(description="笔记", null=True)
create_time = fields.DatetimeField(auto_now_add=True, description='创建时间')
update_time = fields.DatetimeField(auto_now=True, description="更新时间")
auhtor: fields.ForeignKeyRelation["User"] = fields.ForeignKeyField("base.User", related_name="sentence", on_delete=fields.SET_NULL, null=True)

class Meta:
    """
        对该数据库模型类进行相关 配置设置
    """
    table_description = "英语笔记"
    table = "notes"
    # 建立索引
    # 使用联合索引 
    indexes = (("original", "translation"),)


def __str__(self) -> str:
    return self.original # type: ignore

class TimestampMixin(Model):
create_time = fields.DatetimeField(auto_now_add=True, description='创建时间')
update_time = fields.DatetimeField(auto_now=True, description="更新时间")

class Meta:
    # 抽象类 - 继承 避免代码重写,抽象类本身不生成数据表
    abstract = True 
    # table = None  
    # app = "base" 

class User(TimestampMixin):

sentence : fields.ReverseRelation[EnglishSentence]   # 仅用于代码提示,请注意role 必须和 EnglishSentence里面的外键 指定的related_name 同名


user_name = fields.CharField(null=True, max_length=20, description="用户名", unique=True)
user_type = fields.BooleanField(default=False, description="用户类型 True:超级管理员 False:普通管理员")
password = fields.CharField(null=True, max_length=255)
nickname = fields.CharField(default="Boziyoung", max_length=255, description='昵称')
user_phone = fields.CharField(null=True, max_length=11 ,description="手机号", unique=True)
user_email = fields.CharField(max_length=255, description="邮箱", unique=True)
full_name = fields.CharField(max_length=255, null=True, description="姓名")
user_status = fields.IntField(default=0, description='0未激活 1正常 2禁用')
header_img = fields.CharField(null=True, max_length=255, description='头像')
sex = fields.IntField(default=0, null=True, description='0未知 1男 2女')
client_host = fields.CharField(null=True, max_length=19, description="访问IP")

class Meta:
    table_description = "用户表"
    table = "user"
    app = "base"

`
The relationship of the above model is "ForeignKeyField" in EnglishSentence model;

The serialization model is app/model/serializers.py:
`"""
创建各个序列化对象
"""
from app.models.base import EnglishSentence, User
from tortoise.contrib.pydantic.creator import pydantic_model_creator, pydantic_queryset_creator

from tortoise import Tortoise
Tortoise.init_models(["app.models.base"], "models")

admin_english = pydantic_model_creator(EnglishSentence, name= "admin")

list_english = pydantic_queryset_creator(EnglishSentence, name= "list_english", exclude=("notes","create_time", "update_time", "original"))

single_english = pydantic_model_creator(EnglishSentence, name="single_english", exclude=("update_time", "create_time"))

single_english_queryset = pydantic_queryset_creator(EnglishSentence, name="single_english_list", exclude=("notes","create_time", "update_time", "original"))

single_user = pydantic_model_creator(User, name="single_user", exclude=("password", "remarks", "client_host", "create_time", "update_time",))`

i new added a line of code which is "Tortoise.init_models(["app.models.base"], "models")"
but it raised a ConfigurationError

Detailed error :
`WARNING: WatchFiles detected changes in 'app/models/serializers.py'. Reloading...
Process SpawnProcess-35:
Traceback (most recent call last):
File "/home/ubuntu/english/env/lib/python3.11/site-packages/tortoise/init.py", line 119, in get_related_model
return cls.apps[related_app_name][related_model_name]
~~~~~~~~^^^^^^^^^^^^^^^^^^
KeyError: 'base'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/lib/python3.11/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/home/ubuntu/english/env/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started
target(sockets=sockets)
File "/home/ubuntu/english/env/lib/python3.11/site-packages/uvicorn/server.py", line 59, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
File "/home/ubuntu/english/env/lib/python3.11/site-packages/uvicorn/server.py", line 66, in serve
config.load()
File "/home/ubuntu/english/env/lib/python3.11/site-packages/uvicorn/config.py", line 471, in load
self.loaded_app = import_from_string(self.app)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/english/env/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
module = importlib.import_module(module_str)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/importlib/init.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "", line 1206, in _gcd_import
File "", line 1178, in _find_and_load
File "", line 1149, in _find_and_load_unlocked
File "", line 690, in _load_unlocked
File "", line 940, in exec_module
File "", line 241, in _call_with_frames_removed
File "/home/ubuntu/english/english_backend/main.py", line 11, in
from app.core.Router import AllRouter
File "/home/ubuntu/english/english_backend/app/core/Router.py", line 4, in
from app.api.Base import ApiRouter
File "/home/ubuntu/english/english_backend/app/api/Base.py", line 48, in
from app.api.user import user_add, user_del, user_info, get_user_rules, account_login, user_edit, change_password
File "/home/ubuntu/english/english_backend/app/api/user.py", line 14, in
from app.models.serializers import single_user
File "/home/ubuntu/english/english_backend/app/models/serializers.py", line 9, in
Tortoise.init_models(["app.models.base"], "models")
File "/home/ubuntu/english/env/lib/python3.11/site-packages/tortoise/init.py", line 396, in init_models
cls._init_relations()
File "/home/ubuntu/english/env/lib/python3.11/site-packages/tortoise/init.py", line 161, in _init_relations
related_model = get_related_model(related_app_name, related_model_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/english/env/lib/python3.11/site-packages/tortoise/init.py", line 122, in get_related_model
raise ConfigurationError(f"No app with name '{related_app_name}' registered.")
tortoise.exceptions.ConfigurationError: No app with name 'base' registered.
`

Expected results:
I don't know what I should do, I hope you all can help me to solve it; thank you.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with app/models/serializers.py and the Tortoise.init_models call, then compare it with the configuration in app/database/mysql.py and the models in app/models/base.py. Reproduce the reported ConfigurationError and trace how the registered app names relate to the ForeignKeyField declaration. Done means documenting or testing the supported initialization path and its expected result.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, mysql, python
Domain
api, backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.