diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-02-05 16:42:27 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-02-05 16:42:27 -0500 |
| commit | af24660a963c84998d102fb504742d05a9c15146 (patch) | |
| tree | fa979a85b889e93c6419773be15455a57fcf7ba2 /examples/asyncio | |
| parent | 95b3358fabc2b2915e3dc22104e9a224f68e98f9 (diff) | |
| download | sqlalchemy-af24660a963c84998d102fb504742d05a9c15146.tar.gz | |
update asyncio examples and add notes about writeonly
Change-Id: I1233eb1a860b915fb265ec8bf177f1a0471cdbd1
Diffstat (limited to 'examples/asyncio')
| -rw-r--r-- | examples/asyncio/async_orm.py | 41 | ||||
| -rw-r--r-- | examples/asyncio/async_orm_writeonly.py | 102 |
2 files changed, 122 insertions, 21 deletions
diff --git a/examples/asyncio/async_orm.py b/examples/asyncio/async_orm.py index 468891158..66501e545 100644 --- a/examples/asyncio/async_orm.py +++ b/examples/asyncio/async_orm.py @@ -1,20 +1,22 @@ -"""Illustrates use of the sqlalchemy.ext.asyncio.AsyncSession object +"""Illustrates use of the ``sqlalchemy.ext.asyncio.AsyncSession`` object for asynchronous ORM use. """ +from __future__ import annotations import asyncio +import datetime +from typing import List +from typing import Optional -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 async_sessionmaker from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.future import select from sqlalchemy.orm import declarative_base +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship from sqlalchemy.orm import selectinload @@ -24,22 +26,19 @@ Base = declarative_base() class A(Base): __tablename__ = "a" - id = Column(Integer, primary_key=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} + id: Mapped[int] = mapped_column(primary_key=True) + data: Mapped[Optional[str]] + create_date: Mapped[datetime.datetime] = mapped_column( + server_default=func.now() + ) + bs: Mapped[List[B]] = relationship(lazy="raise") class B(Base): __tablename__ = "b" - id = Column(Integer, primary_key=True) - a_id = Column(ForeignKey("a.id")) - data = Column(String) + id: Mapped[int] = mapped_column(primary_key=True) + a_id: Mapped[int] = mapped_column(ForeignKey("a.id")) + data: Mapped[Optional[str]] async def async_main(): @@ -74,10 +73,10 @@ async def async_main(): # AsyncSession.execute() is used for 2.0 style ORM execution # (same as the synchronous API). - result = await session.execute(stmt) + result = await session.scalars(stmt) # result is a buffered Result object. - for a1 in result.scalars(): + for a1 in result: print(a1) print(f"created at: {a1.create_date}") for b1 in a1.bs: @@ -92,9 +91,9 @@ async def async_main(): for b1 in a1.bs: print(b1) - result = await session.execute(select(A).order_by(A.id)) + result = await session.scalars(select(A).order_by(A.id)) - a1 = result.scalars().first() + a1 = result.first() a1.data = "new data" diff --git a/examples/asyncio/async_orm_writeonly.py b/examples/asyncio/async_orm_writeonly.py new file mode 100644 index 000000000..cdc486524 --- /dev/null +++ b/examples/asyncio/async_orm_writeonly.py @@ -0,0 +1,102 @@ +"""Illustrates using **write only relationships** for simpler handling +of ORM collections under asyncio. + +""" +from __future__ import annotations + +import asyncio +import datetime +from typing import Optional + +from sqlalchemy import ForeignKey +from sqlalchemy import func +from sqlalchemy.ext.asyncio import async_sessionmaker +from sqlalchemy.ext.asyncio import create_async_engine +from sqlalchemy.future import select +from sqlalchemy.orm import declarative_base +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column +from sqlalchemy.orm import relationship +from sqlalchemy.orm import WriteOnlyMapped + +Base = declarative_base() + + +class A(Base): + __tablename__ = "a" + + id: Mapped[int] = mapped_column(primary_key=True) + data: Mapped[Optional[str]] + create_date: Mapped[datetime.datetime] = mapped_column( + server_default=func.now() + ) + + # collection relationships are declared with WriteOnlyMapped. There + # is no separate collection type + bs: WriteOnlyMapped[B] = relationship() + + +class B(Base): + __tablename__ = "b" + id: Mapped[int] = mapped_column(primary_key=True) + a_id: Mapped[int] = mapped_column(ForeignKey("a.id")) + data: Mapped[Optional[str]] + + +async def async_main(): + """Main program function.""" + + 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) + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + + async_session = async_sessionmaker(engine, expire_on_commit=False) + + async with async_session() as session: + async with session.begin(): + # WriteOnlyMapped may be populated using any iterable, + # e.g. lists, sets, etc. + session.add_all( + [ + A(bs=[B(), B()], data="a1"), + A(bs=[B()], data="a2"), + A(bs=[B(), B()], data="a3"), + ] + ) + + stmt = select(A) + + result = await session.scalars(stmt) + + for a1 in result: + print(a1) + print(f"created at: {a1.create_date}") + + # to iterate a collection, emit a SELECT statement + for b1 in await session.scalars(a1.bs.select()): + print(b1) + + result = await session.stream(stmt) + + async for a1 in result.scalars(): + print(a1) + + # similar using "streaming" (server side cursors) + async for b1 in (await session.stream(a1.bs.select())).scalars(): + print(b1) + + await session.commit() + result = await session.scalars(select(A).order_by(A.id)) + + a1 = result.first() + + a1.data = "new data" + + +asyncio.run(async_main()) |
