I have two models:
class A(Base):
__tablename__ = 'a'
id = sa.Column(sa.Integer(), primary_key=True)
class B(Base):
__tablename__ = 'b'
id = sa.Column(sa.Integer(), primary_key=True)
a_id = sa.Column(sa.Integer(), sa.ForeignKey(A.id))
a = relationship(A)
Now if i fetch an object from B
and query its a
property with b.a
, i get the error
sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_only() here. Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/14/xd2s)
Putting var = b.a
inside an async with session.begin():
block, or calling it as await b.a
(which is stupid in hindsight, but one must try everything) doesn’t help.
I could do
b_a = (await db.scalars(sa.select(A).filter(A.id == b.a_id))).one()
but it’s too verbose for my taste (and gets really messy for complex relationships).
I found a lot of solutions for the other way around (one-to-many and many-to-many), but nothing for this use case.
Update to answer questions from comments:
I create the engine and the sessionmaker like this:
db_engine = create_async_engine(DB_URI, pool_recycle=3600, pool_pre_ping=True, echo_pool=True)
session_maker = sessionmaker(db_engine, AsyncSession, expire_on_commit=False, autocommit=False, autoflush=False)
And the way i query the object of B
is:
query = sa.select(B).filter(B.id == requested_id)
result = (await db.execute(query)).one_or_none() # type: ignore
b = result[0] if result else None