Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How does the library use asynchronous mode? #32

Open
pylixm opened this issue Mar 24, 2021 · 5 comments
Open

How does the library use asynchronous mode? #32

pylixm opened this issue Mar 24, 2021 · 5 comments

Comments

@pylixm
Copy link

pylixm commented Mar 24, 2021

How does the library use asynchronous mode?

Below is the code I tried, but it not work.

from fastapi import FastAPI
from fastapi_sqlalchemy import DBSessionMiddleware  # middleware helper
from fastapi_sqlalchemy import db  # an object to provide global access to a database session

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

from models.user import User

app = FastAPI()

app.add_middleware(DBSessionMiddleware, db_url="sqlite://", 
                   custom_engine=create_async_engine,
                   session_args={
                        'expire_on_commit': False,
                        'class_': AsyncSession
                   })

# once the middleware is applied, any route can then access the database session
# from the global ``db``

@app.get("/users")
async def get_users():
    users = await db.session.query(User).all()

    return users


if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app=app, host="127.0.0.1", port=8001, log_level="debug")

Does anyone else have any ideas?

@GeekTan
Copy link

GeekTan commented Apr 16, 2021

例如用postgresql 需要配合异步驱动才行,参考sqlalchemy手册的asyncio support

@cwjayroe
Copy link

I think that if you are creating your own engine, you will need to give the middleware the actual async engine object rather than the function to create the engine. Maybe this code will help you (I havent run it but hopefully it'll point you in the right direction).

from fastapi import FastAPI
from fastapi_sqlalchemy import DBSessionMiddleware  # middleware helper
from fastapi_sqlalchemy import db  # an object to provide global access to a database session
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from models.user import User

app = FastAPI()

# async engine object to give to the middleware
engine = create_async_engine('sqlite://')

app.add_middleware(DBSessionMiddleware, 
                   custom_engine=engine,
                   session_args={
                        'expire_on_commit': False,
                        'class_': AsyncSession
                   })

# once the middleware is applied, any route can then access the database session
# from the global ``db``

@app.get("/users")
async def get_users():
    users = await db.session.query(User).all()

    return users


if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app=app, host="127.0.0.1", port=8001, log_level="debug")

@cancan101
Copy link
Contributor

Is that enough or does this library also need to add asynchronous context manager support to DBSession? For example:

class DBSession(metaclass=DBSessionMeta):
    def __init__(self, session_args: Dict = None, commit_on_exit: bool = False):
        self.token = None
        self.session_args = session_args or {}
        self.commit_on_exit = commit_on_exit

    async def __aenter__(self):
        if not isinstance(_Session, sessionmaker):
            raise SessionNotInitialisedError
        self.token = _session.set(_Session(**self.session_args))
        return type(self)

    async def __aexit__(self, exc_type, exc_value, traceback):
        sess = _session.get()
        if exc_type is not None:
            await sess.rollback()

        if self.commit_on_exit:
            await sess.commit()

        await sess.close()
        _session.reset(self.token)

and then tweak the dispatch in the middleware:

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
        async with db(commit_on_exit=self.commit_on_exit):
            response = await call_next(request)
        return response

@h0rn3t
Copy link

h0rn3t commented Oct 23, 2021

@pylixm https://github.com/h0rn3t/fastapi-async-sqlalchemy u can try this

@hadrien
Copy link

hadrien commented Aug 16, 2023

@pylixm I'm late to the party: Check https://github.com/dialoguemd/fastapi-sqla/ as well. It's compatible with sqla 1.3, 1.4, 2.0 and with async support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants