tortoise-orm icon indicating copy to clipboard operation
tortoise-orm copied to clipboard

register_tortoise() is not compatible with lifespan in fastapis>=0.95.0

Open wu-clan opened this issue 2 years ago • 4 comments

Describe the bug when use lifespan with register_tortoise() in fastapi >= 0.95.0, register_tortoise() is not work

wu-clan avatar Apr 07 '23 04:04 wu-clan

https://tortoise.github.io/examples/fastapi.html

This example worked with fastapi-0.95.1 and tortoise-orm-0.19.3

You may need to describe the bug with detail code @wu-clan

waketzheng avatar May 10 '23 15:05 waketzheng

Looks like lifespan can only pass into FastAPI when init

long2ice avatar May 12 '23 07:05 long2ice

An example for tortoise-orm<=0.19.3

from contextlib import AbstractAsyncContextManager, asynccontextmanager
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
from tortoise.log import logger


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)
        logger.info("Tortoise-ORM started, %s, %s", connections._get_storage(), Tortoise.apps)
        if generate_schemas:
            logger.info("Tortoise-ORM generating schema")
            await Tortoise.generate_schemas()

    async def close_orm() -> None:  # pylint: disable=W0612
        await connections.close_all()
        logger.info("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()


@asynccontextmanager
async def lifespan(app: FastAPI):
    # do sth before db inited
    async with register_tortoise(
        app,
        db_url="sqlite://:memory:",
        modules={"models": ["models"]},
        generate_schemas=True,
        add_exception_handlers=True,
    ):
        # do sth while db connected
        yield
    # do sth after db closed


app = FastAPI(title="Tortoise ORM FastAPI example", lifespan=lifespan)

waketzheng avatar Jul 18 '23 12:07 waketzheng

https://tortoise.github.io/examples/fastapi.html

This example worked with fastapi-0.95.1 and tortoise-orm-0.19.3

You may need to describe the bug with detail code @wu-clan

Does this example still work without getting missing created_at and updated_at fields error?

i701 avatar Sep 23 '23 16:09 i701

Added lifespan support in 0.21.0

abondar avatar May 24 '24 07:05 abondar