Python 用FastAPI简单注册Tortoise-ORM模型

Python 用FastAPI简单注册Tortoise-ORM模型,python,fastapi,tortoise-orm,Python,Fastapi,Tortoise Orm,我有一个FastAPI应用程序和一个现有的MySQL数据库,我正在尝试使用Ortoise 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 DATA

我有一个FastAPI应用程序和一个现有的MySQL数据库,我正在尝试使用Ortoise 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"))
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"
# Test SQL query
from models import Store

@app.on_event("startup")
async def startup():
    print(await Store.get(api_key="api_key"))
…和一个models.py文件,位于相同的基本目录级别,如下所示:

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"))
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"
# Test SQL query
from models import Store

@app.on_event("startup")
async def startup():
    print(await Store.get(api_key="api_key"))
但是,我从乌龟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
知道为什么吗

我遵循doc(),但是“应该为模型发现的模块”的路径/语法对我来说不是很清楚。我还尝试向
pydantic\u model\u creator
注册模型,但文档中不清楚您为什么需要它()。
我不希望使用由register_tortoise加载的config.json完整配置文件,根据文档,它似乎是可选的。

问题来自FastAPI和tortoise ORM的异步特性。 我们必须等待FastAPI加载,等待龟龟注册模型

因此,我们可以成功地执行一个异步请求,等待加载FastAPI,并请求Ortoise ORM,如下所示:

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"))
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"
# Test SQL query
from models import Store

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

问题来自FastAPI和Ortoise ORM的异步特性。 我们必须等待FastAPI加载,等待龟龟注册模型

因此,我们可以成功地执行一个异步请求,等待加载FastAPI,并请求Ortoise ORM,如下所示:

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"))
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"
# 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寿命事件(即
启动
)的触发,并且没有注册模型。我们最后修补了中间件,使其仅在
scope['type']
==
'http'
时启动

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

如果在使用lifespan.startup消息或lifespan类型的作用域调用可调用的应用程序时引发异常,则服务器必须继续,但不发送任何lifespan事件

然而,乌龟ORM
注册\乌龟
功能依赖寿命事件
启动
来注册模型。因此,我认为uvicorn的寿命模式应该是
on
,而不是默认的
auto
。这样,您的服务器进程将终止,而不是为配置错误的应用程序提供服务

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

在我们的例子中,一个ASGI中间件(不支持ASGI寿命事件)在启动期间引发了一个错误,该错误阻止了ASGI寿命事件(即
启动
)的触发,并且没有注册模型。我们最后修补了中间件,使其仅在
scope['type']
==
'http'
时启动

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

如果在使用lifespan.startup消息或lifespan类型的作用域调用可调用的应用程序时引发异常,则服务器必须继续,但不发送任何lifespan事件

然而,乌龟ORM
注册\乌龟
功能依赖寿命事件
启动
来注册模型。因此,我认为uvicorn的寿命模式应该是
on
,而不是默认的
auto
。这样,您的服务器进程将终止,而不是为配置错误的应用程序提供服务

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

你在哪里运行应用程序?这可能是因为您在
app.py
文件上方的一个级别上启动它,因此需要在
models.py
文件上方一个级别上启动它。如果您有
app/main.py
app/models.py
,那么路径是
app.models
我没有使用任何
app.py
文件,FastAPI应用程序在
main.py
中实例化为
app
,并且
models.py
文件与
main.py
处于同一级别。然后使用
main.py
更改
app.py
。运行该命令时,终端指向何处?在与
main.py
相同的级别上或在上面的级别上?关于在终端中运行的命令,它与
main.py
models.py
在相同的级别上运行。关于
main.py
,我不明白你的意思,因为一切都在同一个级别。1)这很奇怪。您的数据库中是否存在该架构?2) 因为我不知道你的主文件是如何调用的,所以我给它起了一个名字
app.py
,但是因为你指出它
main.py
,我只是简单地更改了它。你从哪里运行这个应用程序?这可能是因为您在
app.py
文件上方的一个级别上启动它,因此需要在
models.py
文件上方一个级别上启动它。如果您有
app/main.py
app/models.py
,那么路径是
app.models
我没有使用任何
app.py
文件,FastAPI应用程序在
main.py
中实例化为
app
,并且
models.py
文件与
main.py
处于同一级别。然后使用
main.py
更改
app.py
。运行该命令时,终端指向何处?在与
main.py
相同的级别上或在上面的级别上?关于在终端中运行的命令,它与
main.py
models.py
在相同的级别上运行。关于
main.py
,我不明白你的意思,因为一切都在同一个级别。1)这很奇怪。您的数据库中是否存在该架构?2) 因为我不知道主文件是如何调用的,所以我给它命名为
app.py
,但是因为你指出它
main.py
,我只是简单地更改了它。这是启动数据库连接的方法吗?通过提出请求?我们如何关闭?不,你必须先注册乌龟。这只是在发出请求之前等待启动。问题是,这是启动数据库连接的方法吗?通过提出请求?我们如何关闭?不,你必须先注册乌龟。这只是在发出请求之前等待启动。我有一个问题