【问题标题】:What’s the right way to use PonyOrm with FastApi?将 PonyOrm 与 FastApi 一起使用的正确方法是什么?
【发布时间】:2020-11-15 12:46:10
【问题描述】:

对于个人项目,我将 PonyOrm 与 FastApi 一起使用;有没有一种经典的方法可以在端点的整个异步生命周期调用中保持 db_session ?

PonyOrm 的文档中谈到了使用装饰器和产量;但它对我不起作用,所以在查看了其他 Github 项目后,我发现这个解决方法效果很好。

但我真的不知道幕后发生了什么,以及为什么 Pony 的文档对异步主题不准确。

def _enter_session():
    session = db_session(sql_debug=True)
    Request.pony_session = session
    session.__enter__()


def _exit_session():
    session = getattr(Request, 'pony_session', None)
    if session is not None:
        session.__exit__()


@app.middleware("http")
async def add_pony(request: Request, call_next):
    _enter_session()
    response = await call_next(request)
    _exit_session()
    return response

然后在一个依赖中,例如:

async def current_user(
        username: str = Depends(current_user_from_token)) -> User:

    with Request.pony_session:
        # db actions 

在端点调用中:

@router.post("/token", response_model=Token)
async def login_for_access_token(
        request: Request,
        user_agent: Optional[str] = Header(None),
        form_data: OAuth2PasswordRequestForm = Depends()):

    status: bool = authenticate_user(
        form_data.username,
        form_data.password,
        request.client.host,
        user_agent)


@db_session
def authenticate_user(
        username: str,
        password: str,
        client_ip: str = 'Undefined',
        client_app: str = 'Undefined'):
    user: User = User.get(email=username)

如果你们有更好的方法或好的解释,我很想听听 :)

【问题讨论】:

标签: python-asyncio fastapi ponyorm


【解决方案1】:

我有点像 PonyORM 开发人员和 FastAPI 用户。

async 和 Pony 的问题在于 Pony 使用我们理解的原子事务。此外,如果上下文将切换到另一个协程,我们还使用可以在另一个会话中使用的线程本地缓存。 我同意我们应该在文档中添加有关它的信息。

为确保一切正常,您应该使用 db_session 作为上下文管理器,并确保在此代码块中没有异步调用。

如果您的端点不是异步的,您也可以为它们使用db_session 装饰器。

在 Pony 中,我们同意在某些情况下使用 ContextVar 代替 Local 应该会有所帮助。

一句话的答案是:使用短暂的会话,不要用异步来打断它们。

【讨论】:

  • 感谢您的回答:)
  • 再问一个问题,你觉得我的方法好吗?我仍然收到随机 HTTP 500,例如:文件“/usr/local/lib/python3.8/site-packages/pony/orm/core.py”,第 475 行,在 exit 断言本地。 db_session 是 db_session AssertionError
  • 我回答后你的方法有改变吗?如果是 - 如何?
  • 你好。不,没有任何改变。
  • 所以你的问题是 db_session 内部使用 async 的装饰器。你需要用db_session上下文管理器替换它
【解决方案2】:

尝试使用标准的 fastapi 依赖:

from fastapi import Depends

async def get_pony():
    with db_session(sql_debug=True) as session:
        yield session


async def current_user(
    username: str = Depends(current_user_from_token),
    pony_session = Depends(get_pony)) -> User:

    with pony_session:
        # db actions 

【讨论】:

  • 感谢您的回答 :) 这段代码对我不起作用,我想我会坚持同步操作并将 db_session 保留在中间件中 :)
猜你喜欢
  • 2018-04-10
  • 2013-01-02
  • 2020-08-27
  • 2020-07-10
  • 2020-09-29
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多