From 2d185f516bcf08c97f8902218911c0750b6427a7 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 27 Nov 2021 14:29:00 -0500 Subject: [PATCH] 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 (cherry picked from commit 29c5fba9ad89e53180f0bd2a026742321093105f) --- doc/build/changelog/migration_20.rst | 64 +++++++++++++++++++++++++++- doc/build/orm/collections.rst | 8 ++-- doc/build/orm/extensions/asyncio.rst | 4 ++ doc/build/orm/queryguide.rst | 2 +- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/doc/build/changelog/migration_20.rst b/doc/build/changelog/migration_20.rst index 79e198d09c..8f35220d89 100644 --- a/doc/build/changelog/migration_20.rst +++ b/doc/build/changelog/migration_20.rst @@ -260,12 +260,12 @@ the SQLAlchemy project itself, the approach taken is as follows: import warnings from sqlalchemy import exc - + # for warnings not included in regex-based filter below, just log warnings.filterwarnings( "always", category=exc.RemovedIn20Warning ) - + # for warnings related to execute() / scalar(), raise for msg in [ r"The (?:Executable|Engine)\.(?:execute|scalar)\(\) function", @@ -1966,6 +1966,66 @@ 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 bc98b4b41d..31db0b2616 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 a10af53ba1..91c0b31198 100644 --- a/doc/build/orm/queryguide.rst +++ b/doc/build/orm/queryguide.rst @@ -1081,4 +1081,4 @@ matching objects locally present in the :class:`_orm.Session`. See the section .. Setup code, not for display >>> conn.close() - ROLLBACK \ No newline at end of file + ROLLBACK -- 2.47.3