import asyncio
+ from sqlalchemy import Column
+ from sqlalchemy import MetaData
+ from sqlalchemy import select
+ from sqlalchemy import String
+ from sqlalchemy import Table
from sqlalchemy.ext.asyncio import create_async_engine
+ meta = MetaData()
+ t1 = Table("t1", meta, Column("name", String(50), primary_key=True))
- async def async_main():
+
+ async def async_main() -> None:
engine = create_async_engine(
"postgresql+asyncpg://scott:tiger@localhost/test",
echo=True,
)
async with engine.begin() as conn:
- await conn.run_sync(meta.drop_all)
await conn.run_sync(meta.create_all)
await conn.execute(
section :ref:`asyncio_orm_avoid_lazyloads` details this. The example below
illustrates a complete example including mapper and session configuration::
+ from __future__ import annotations
+
import asyncio
+ import datetime
- from sqlalchemy import DateTime
from sqlalchemy import ForeignKey
from sqlalchemy import func
- from sqlalchemy import Integer
from sqlalchemy import select
- from sqlalchemy import String
from sqlalchemy.ext.asyncio import async_sessionmaker
+ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import DeclarativeBase
+ from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.orm import selectinload
class A(Base):
__tablename__ = "a"
- id = mapped_column(Integer, primary_key=True)
- data = mapped_column(String)
- create_date = mapped_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}
+ id: Mapped[int] = mapped_column(primary_key=True)
+ data: Mapped[str]
+ create_date: Mapped[datetime.datetime] = mapped_column(server_default=func.now())
+ bs: Mapped[list[B]] = relationship()
class B(Base):
__tablename__ = "b"
- id = mapped_column(Integer, primary_key=True)
- a_id = mapped_column(ForeignKey("a.id"))
- data = mapped_column(String)
-
+ id: Mapped[int] = mapped_column(primary_key=True)
+ a_id: Mapped[int] = mapped_column(ForeignKey("a.id"))
+ data: Mapped[str]
- async def async_main():
- engine = create_async_engine(
- "postgresql+asyncpg://scott:tiger@localhost/test",
- echo=True,
- )
-
- async with engine.begin() as conn:
- await conn.run_sync(Base.metadata.drop_all)
- await conn.run_sync(Base.metadata.create_all)
- # expire_on_commit=False will prevent attributes from being expired
- # after commit.
- async_session = async_sessionmaker(engine, expire_on_commit=False)
+ async def insert_objects(async_session: async_sessionmaker[AsyncSession]) -> None:
async with async_session() as session:
async with session.begin():
]
)
+
+ async def select_and_update_objects(
+ async_session: async_sessionmaker[AsyncSession],
+ ) -> None:
+
+ async with async_session() as session:
stmt = select(A).options(selectinload(A.bs))
result = await session.execute(stmt)
for b1 in a1.bs:
print(b1)
- result = await session.execute(select(A).order_by(A.id))
+ result = await session.execute(select(A).order_by(A.id).limit(1))
- a1 = result.scalars().first()
+ a1 = result.scalars().one()
a1.data = "new data"
# expire_on_commit=False allows
print(a1.data)
+
+ async def async_main() -> None:
+ engine = create_async_engine(
+ "postgresql+asyncpg://scott:tiger@localhost/test",
+ echo=True,
+ )
+
+ # async_sessionmaker: a factory for new AsyncSession objects.
+ # expire_on_commit - don't expire objects after transaction commit
+ async_session = async_sessionmaker(engine, expire_on_commit=False)
+
+ async with engine.begin() as conn:
+ await conn.run_sync(Base.metadata.create_all)
+
+ await insert_objects(async_session)
+ await select_and_update_objects(async_session)
+
# for AsyncEngine created in function scope, close and
# clean-up pooled connections
await engine.dispose()
asyncio.run(async_main())
In the example above, the :class:`_asyncio.AsyncSession` is instantiated using
-the optional :class:`_asyncio.async_sessionmaker` helper, and associated with an
-:class:`_asyncio.AsyncEngine` against particular database URL. It is
-then used in a Python asynchronous context manager (i.e. ``async with:``
-statement) so that it is automatically closed at the end of the block; this is
-equivalent to calling the :meth:`_asyncio.AsyncSession.close` method.
+the optional :class:`_asyncio.async_sessionmaker` helper, which provides
+a factory for new :class:`_asyncio.AsyncSession` objects with a fixed set
+of parameters, which here includes associating it with
+an :class:`_asyncio.AsyncEngine` against particular database URL. It is then
+passed to other methods where it may be used in a Python asynchronous context
+manager (i.e. ``async with:`` statement) so that it is automatically closed at
+the end of the block; this is equivalent to calling the
+:meth:`_asyncio.AsyncSession.close` method.
.. _asyncio_orm_avoid_lazyloads:
e.g.::
from sqlalchemy.ext.asyncio import create_async_engine
+ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import async_sessionmaker
- async def main():
+ async def run_some_sql(async_session: async_sessionmaker[AsyncSession]) -> None:
+ async with async_session() as session:
+ session.add(SomeObject(data="object"))
+ session.add(SomeOtherObject(name="other object"))
+ await session.commit()
+
+ async def main() -> None:
# an AsyncEngine, which the AsyncSession will use for connection
# resources
engine = create_async_engine('postgresql+asyncpg://scott:tiger@localhost/')
- AsyncSession = async_sessionmaker(engine)
+ # create a reusable factory for new AsyncSession instances
+ async_session = async_sessionmaker(engine)
- async with async_session() as session:
- session.add(some_object)
- session.add(some_other_object)
- await session.commit()
+ await run_some_sql(async_session)
+
+ await engine.dispose()
+
+ The :class:`.async_sessionmaker` is useful so that different parts
+ of a program can create new :class:`.AsyncSession` objects with a
+ fixed configuration established up front. Note that :class:`.AsyncSession`
+ objects may also be instantiated directly when not using
+ :class:`.async_sessionmaker`.
- .. versionadded:: 2.0 :class:`.asyncio_sessionmaker` provides a
+ .. versionadded:: 2.0 :class:`.async_sessionmaker` provides a
:class:`.sessionmaker` class that's dedicated to the
:class:`.AsyncSession` object, including pep-484 typing support.