From: Mike Bayer Date: Sat, 27 Nov 2021 19:29:00 +0000 (-0500) Subject: update migration strategy for dynamic loaders X-Git-Tag: rel_2_0_0b1~630 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=29c5fba9ad89e53180f0bd2a026742321093105f;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git update migration strategy for dynamic loaders discuss the two current ways for this use case that use 2.0 style querying and introduce that a newer API is likely on the way. Also repair autofunctions for with_parent for 2.0 only. References: #7123 References: #7372 Change-Id: I2ff6cfd780540ee4ee887b61137af7afa1327a9f --- diff --git a/doc/build/changelog/migration_20.rst b/doc/build/changelog/migration_20.rst index 1c01698886..5fdd093d0b 100644 --- a/doc/build/changelog/migration_20.rst +++ b/doc/build/changelog/migration_20.rst @@ -2049,6 +2049,65 @@ the :func:`_orm.selectinload` strategy presents a collection-oriented eager loader that is superior in most respects to :func:`_orm.joinedload` and should be preferred. +.. _migration_20_dynamic_loaders: + +Making use of "dynamic" relationship loads without using Query +--------------------------------------------------------------- + +**Synopsis** + +The ``lazy="dynamic"`` relationship loader strategy, discussed at +:ref:`dynamic_relationship`, makes use of the :class:`_query.Query` object +which is legacy in 2.0. + + +**Migration to 2.0** + +This pattern is still under adjustment for SQLAlchemy 2.0, and it is expected +that new APIs will be introduced. In the interim, there are two ways +to achieve 2.0 style querying that's in terms of a specific relationship: + +* Make use of the :attr:`_orm.Query.statement` attribute on an existing + ``lazy="dynamic"`` relationship. We can use methods like + :meth:`_orm.Session.scalars` with the dynamic loader straight away as + follows:: + + + class User(Base): + __tablename__ = 'user' + + posts = relationship(Post, lazy="dynamic") + + jack = session.get(User, 5) + + # filter Jack's blog posts + posts = session.scalars( + jack.posts.statement.where(Post.headline == "this is a post") + ) + +* Use the :func:`_orm.with_parent` function to construct a :func:`_sql.select` + construct directly:: + + from sqlalchemy.orm import with_parent + + jack = session.get(User, 5) + + posts = session.scalars( + select(Post). + where(with_parent(jack, User.posts)). + where(Post.headline == "this is a post") + ) + +**Discussion** + +The original idea was that the :func:`_orm.with_parent` function should be +sufficient, however continuing to make use of special attributes on the +relationship itself remains appealing, and there's no reason a 2.0 style +construct can't be made to work here as well. There will likely be a new +loader strategy name that sets up an API similar to the example above that +uses the ``.statement`` attribute, such as +``jack.posts.select().where(Post.headline == 'headline')``. + .. _migration_20_session_autocommit: Autocommit mode removed from Session; autobegin support added diff --git a/doc/build/orm/collections.rst b/doc/build/orm/collections.rst index a811779afa..9640891976 100644 --- a/doc/build/orm/collections.rst +++ b/doc/build/orm/collections.rst @@ -32,10 +32,10 @@ loading of child items both at load time as well as deletion time. Dynamic Relationship Loaders ---------------------------- -.. note:: This is a legacy feature. Using the :func:`_orm.with_parent` - filter in conjunction with :func:`_sql.select` is the :term:`2.0 style` - method of use. For relationships that shouldn't load, set - :paramref:`_orm.relationship.lazy` to ``noload``. +.. note:: SQLAlchemy 2.0 will have a slightly altered pattern for "dynamic" + loaders that does not rely upon the :class:`_orm.Query` object, which + will be legacy in 2.0. For current migration strategies, + see :ref:`migration_20_dynamic_loaders`. .. note:: This loader is in the general case not compatible with the :ref:`asyncio_toplevel` extension. It can be used with some limitations, as indicated in :ref:`Asyncio dynamic guidelines `. diff --git a/doc/build/orm/extensions/asyncio.rst b/doc/build/orm/extensions/asyncio.rst index fcaf104467..91c7c53e1e 100644 --- a/doc/build/orm/extensions/asyncio.rst +++ b/doc/build/orm/extensions/asyncio.rst @@ -343,6 +343,10 @@ Other guidelines include: ) addresses_filter = (await session.scalars(stmt)).all() + .. seealso:: + + :ref:`migration_20_dynamic_loaders` - notes on migration to 2.0 style + .. _session_run_sync: Running Synchronous Methods and Functions under asyncio diff --git a/doc/build/orm/queryguide.rst b/doc/build/orm/queryguide.rst index a5b8813df9..f2839547fb 100644 --- a/doc/build/orm/queryguide.rst +++ b/doc/build/orm/queryguide.rst @@ -1116,9 +1116,9 @@ Additional ORM API Constructs .. autofunction:: sqlalchemy.orm.with_loader_criteria -.. autofunction:: join +.. autofunction:: sqlalchemy.orm.join -.. autofunction:: outerjoin +.. autofunction:: sqlalchemy.orm.outerjoin -.. autofunction:: with_parent +.. autofunction:: sqlalchemy.orm.with_parent