使用 FastAPI 简单注册 Tortoise ORM 模型

Simple registering of Tortoise ORM models with FastAPI

我有一个带有现有 MySQL 数据库的 FastAPI 应用程序,我正在尝试使用 Tortoise ORM。 (简化的)主要 FastAPI 文件如下所示:

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

# Register FastAPI main app
app = FastAPI(title="my_app")


# Database
DATABASE_URL = "mysql://{}:{}@{}:{}/{}".format(
    os.environ["MYSQL_USER"],
    os.environ["MYSQL_PASSWORD"],
    os.environ.get("MYSQL_HOST", "127.0.0.1"),
    os.environ.get("MYSQL_PORT", "3306"),
    os.environ.get("MYSQL_DB", "my_db"),
)

# Register Tortoise ORM with DB
register_tortoise(
    app,
    db_url=DATABASE_URL,
    modules={"models": ["models"]},
    generate_schemas=False,
    add_exception_handlers=True,
)


# Test SQL query
from models import Store
print(Store.get(api_key="api_key"))

...和一个 models.py 文件,位于同一基目录级别,如下所示:

from tortoise import fields
from tortoise.models import Model


class Store(Model):
    api_key = fields.CharField(max_length=64, db_index=True)
    name = fields.CharField(max_length=255)

    def __str__(self):
        return self.name

    class Meta:
        table = "stores"

但是,我从 Tortoise ORM 得到一个错误:

  File ".../site-packages/tortoise/models.py", line 265, in db
    raise ConfigurationError("No DB associated to model")
tortoise.exceptions.ConfigurationError: No DB associated to model

知道为什么吗?

我正在关注文档 (https://tortoise-orm.readthedocs.io/en/latest/contrib/fastapi.html) but the path/syntax for "modules that should be discovered for models" is not very clear to me. I also tried with registering the models with pydantic_model_creator, though not clear in the doc why you need that (https://tortoise-orm.readthedocs.io/en/latest/examples/fastapi.html#example-fastapi)。 我不想使用 register_tortoise 加载的 config.json 完整配置文件,根据文档,它似乎是可选的。

问题出在 FastAPI 和 Tortoise ORM 的异步特性上。 我们必须等待 FastAPI 加载和 Tortoise 注册模型。

因此我们可以成功地执行等待 FastAPI 加载的异步请求,以及 Tortoise ORM 请求,如下所示:

# Test SQL query
from models import Store

@app.on_event("startup")
async def startup():
    print(await Store.get(api_key="api_key"))

在我们的案例中,其中一个 ASGI 中间件(不支持 asgi 生命周期事件)在启动期间引发错误,这阻止了 ASGI 生命周期事件(即 startup)触发并且没有注册楷模。我们最终修补了仅在 scope['type'] == 'http'.

时触发的中间件

ASGI spec 声明即使在启动错误后服务器也必须继续。

If an exception is raised when calling the application callable with a lifespan.startup message or a scope with type lifespan, the server must continue but not send any lifespan events.

然而,乌龟 ORM register_tortoise 函数依赖生命周期事件 startup 来注册模型。所以我觉得uvicorn上的生命周期模式应该是on而不是默认的auto。这样您的服务器进程将终止而不是服务于配置错误的应用程序。

uvicorn.run("start_server:app", host="0.0.0.0", port=8080, log_level="info", lifespan='on')