Closed daudln closed 4 months ago
I can confirm that I am using fastapi version 0.110.0 with tortoise orm 0.20.0 and lifespan.
The error NoneType' object is not iterable
is due to the fact that the connection is not registered when you run the query
This is the solution I am currently using:
in my module: config_db.py
from contextlib import AbstractAsyncContextManager
from types import ModuleType
from typing import Dict, Iterable, Optional, Union
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from tortoise import Tortoise, connections
from tortoise.exceptions import DoesNotExist, IntegrityError
def register_tortoise(
app: FastAPI,
config: Optional[dict] = None,
config_file: Optional[str] = None,
db_url: Optional[str] = None,
modules: Optional[Dict[str, Iterable[Union[str, ModuleType]]]] = None,
generate_schemas: bool = False,
add_exception_handlers: bool = False,
) -> AbstractAsyncContextManager:
async def init_orm() -> None: # pylint: disable=W0612
await Tortoise.init(
config=config, config_file=config_file, db_url=db_url, modules=modules
)
print(f"Tortoise-ORM started, {connections._get_storage()}")
if generate_schemas:
print("Tortoise-ORM generating schema")
await Tortoise.generate_schemas()
async def close_orm() -> None: # pylint: disable=W0612
await connections.close_all()
print("Tortoise-ORM shutdown")
class Manager(AbstractAsyncContextManager):
async def __aenter__(self) -> "Manager":
await init_orm()
return self
async def __aexit__(self, *args, **kwargs) -> None:
await close_orm()
if add_exception_handlers:
@app.exception_handler(DoesNotExist)
async def doesnotexist_exception_handler(request: Request, exc: DoesNotExist):
return JSONResponse(status_code=404, content={"detail": str(exc)})
@app.exception_handler(IntegrityError)
async def integrityerror_exception_handler(
request: Request, exc: IntegrityError
):
return JSONResponse(
status_code=422,
content={
"detail": [{"loc": [], "msg": str(exc), "type": "IntegrityError"}]
},
)
return Manager()
in main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from .config_db import register_tortoise
@asynccontextmanager
async def lifespan(app: FastAPI):
print("=========== Start REST API ===========")
async with register_tortoise(
app,
db_url="sqlite://data.sqlite3",
modules={"models": [__name__]},
generate_schemas=True,
add_exception_handlers=True,
):
# your starting logic here...
yield
print("=========== Stop REST API ===========")
# your stop logic here
app = FastAPI(lifespan=lifespan)
thanks ,i got it @vlakius
I have created a discussion about this question. https://github.com/tiangolo/fastapi/discussions/11507 From where I stand, the reason is lifespan will transform the function covered by @app.onevent("startup") . the consequence is that these functions will run as soon as app have initialed. BUT, these function might need run before some app-middleware applied, or need run after page logical function (such as this register_tortoise), SO I think fastapi should consider add some hooks to manage the life cycle.
Just a heads up, the PR #1541 addressing the Tortoise ORM v0.21.0 integration with FastAPI lifespan issue has been merged. 🎉 As a result, I'm going to go ahead and close the associated issue.
Describe the bug I'm encountering an issue where app_lifespan doesn't seem to work correctly with Tortoise ORM. The issue appears to be related to a potential incompatibility in FastAPI (see Discussion fastapi/discussions/#11375 in the FastAPI repository). I've included more details about the problem in the FastAPI issue report.
To Reproduce
Additional context
OS Ubuntu 23.10
Dependencies