首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用异步sqlalchemy访问关系?

如何使用异步sqlalchemy访问关系?
EN

Stack Overflow用户
提问于 2021-11-25 01:35:25
回答 1查看 3.7K关注 0票数 4
代码语言:javascript
运行
复制
import asyncio

from sqlalchemy import Column
from sqlalchemy import DateTime
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.future import select
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import selectinload
from sqlalchemy.orm import sessionmaker

engine = create_async_engine(
        "postgresql+asyncpg://user:pass@localhost/db",
        echo=True,
    )


# expire_on_commit=False will prevent attributes from being expired
# after commit.
async_session = sessionmaker(
    engine, expire_on_commit=False, class_=AsyncSession
)


Base = declarative_base()

class A(Base):
    __tablename__ = "a"

    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True)
    data = Column(String)
    create_date = Column(DateTime, server_default=func.now())
    bs = relationship("B")

    # required in order to access columns with server defaults
    # or SQL expression defaults, subsequent to a flush, without
    # triggering an expired load
    __mapper_args__ = {"eager_defaults": True}


class B(Base):
    __tablename__ = "b"
    id = Column(Integer, primary_key=True)
    a_id = Column(ForeignKey("a.id"))
    data = Column(String)
    
    
       

async with engine.begin() as conn:
    await conn.run_sync(Base.metadata.drop_all)
    await conn.run_sync(Base.metadata.create_all)


async with async_session() as session:
    async with session.begin():
        session.add_all(
            [
                A(bs=[B(), B()], data="a1"),
                A(bs=[B()], data="a2"),
            ]
        )


async with async_session() as session:
    result = await session.execute(select(A).order_by(A.id))
    a1 = result.scalars().first()

    # no issue: 
    print(a1.name, a1.data)

    # throws error:
    print(a1.bs)

试图访问a1.bs会导致以下错误:

代码语言:javascript
运行
复制
     59     current = greenlet.getcurrent()
     60     if not isinstance(current, _AsyncIoGreenlet):
---> 61         raise exc.MissingGreenlet(
     62             "greenlet_spawn has not been called; can't call await_() here. "
     63             "Was IO attempted in an unexpected place?"

MissingGreenlet: greenlet_spawn has not been called; can't call await_() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/14/xd2s)
EN

Stack Overflow用户

回答已采纳

发布于 2021-11-25 03:07:08

如下所示:

代码语言:javascript
运行
复制
from sqlalchemy.orm import selectinload

async with async_session() as session:
    result = await session.execute(select(A).order_by(A.id)
                                            .options(selectinload(A.bs)))
    a = result.scalars().first()

    print(a.bs)

键正在使用selectinload method to prevent implicit IO

更新

有一些替代selectinload的方法,如joinedloadlazyload。我仍在努力理解其中的差异。

票数 10
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70104873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档