diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-09-25 22:31:16 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-10-31 13:44:53 -0400 |
commit | 654b462d668a2ced4e87077b9babb2590acbf983 (patch) | |
tree | 8b6023480423e990c9bbca7c280cb1cb58e012fc /lib/sqlalchemy/orm | |
parent | 841eb216644202567ebddfc0badc51a3a35e98c3 (diff) | |
download | sqlalchemy-review/mike_bayer/tutorial20.tar.gz |
tutorial 2.0 WIPreview/mike_bayer/tutorial20
Add SelectBase.exists() method as it seems strange this is
not available already. The Exists construct itself does
not provide full SELECT-building capabilities so it makes
sense this should be used more like a scalar_subquery.
Make sure stream_results is getting set up when yield_per
is used, for 2.0 style statements as well. this was
hardcoded inside of Query.yield_per() and is now moved
to take place within QueryContext.
Change-Id: Icafcd4fd9b708772343d56edf40995c9e8f835d6
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r-- | lib/sqlalchemy/orm/context.py | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/query.py | 87 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/session.py | 21 |
4 files changed, 31 insertions, 89 deletions
diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py index 5e9cf9cce..12759f018 100644 --- a/lib/sqlalchemy/orm/context.py +++ b/lib/sqlalchemy/orm/context.py @@ -216,6 +216,16 @@ class ORMCompileState(CompileState): statement._execution_options, ) + if "yield_per" in execution_options or load_options._yield_per: + execution_options = execution_options.union( + { + "stream_results": True, + "max_row_buffer": execution_options.get( + "yield_per", load_options._yield_per + ), + } + ) + bind_arguments["clause"] = statement # new in 1.4 - the coercions system is leveraged to allow the diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index b1ff1a049..64f561cbd 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -499,6 +499,8 @@ class PropComparator(operators.ColumnOperators): .. seealso:: + :ref:`orm_queryguide_join_on_augmented` + :ref:`loader_option_criteria` :func:`.with_loader_criteria` diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 277dda6fb..f79c19849 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -770,66 +770,18 @@ class Query( (e.g. approximately 1000) is used, even with DBAPIs that buffer rows (which are most). - The :meth:`_query.Query.yield_per` method **is not compatible - subqueryload eager loading or joinedload eager loading when - using collections**. It is potentially compatible with "select in" - eager loading, **provided the database driver supports multiple, - independent cursors** (pysqlite and psycopg2 are known to work, - MySQL and SQL Server ODBC drivers do not). - - Therefore in some cases, it may be helpful to disable - eager loads, either unconditionally with - :meth:`_query.Query.enable_eagerloads`:: - - q = sess.query(Object).yield_per(100).enable_eagerloads(False) - - Or more selectively using :func:`.lazyload`; such as with - an asterisk to specify the default loader scheme:: - - q = sess.query(Object).yield_per(100).\ - options(lazyload('*'), joinedload(Object.some_related)) - - .. warning:: - - Use this method with caution; if the same instance is - present in more than one batch of rows, end-user changes - to attributes will be overwritten. - - In particular, it's usually impossible to use this setting - with eagerly loaded collections (i.e. any lazy='joined' or - 'subquery') since those collections will be cleared for a - new load when encountered in a subsequent result batch. - In the case of 'subquery' loading, the full result for all - rows is fetched which generally defeats the purpose of - :meth:`~sqlalchemy.orm.query.Query.yield_per`. - - Also note that while - :meth:`~sqlalchemy.orm.query.Query.yield_per` will set the - ``stream_results`` execution option to True, currently - this is only understood by - :mod:`~sqlalchemy.dialects.postgresql.psycopg2`, - :mod:`~sqlalchemy.dialects.mysql.mysqldb` and - :mod:`~sqlalchemy.dialects.mysql.pymysql` dialects - which will stream results using server side cursors - instead of pre-buffer all rows for this query. Other - DBAPIs **pre-buffer all rows** before making them - available. The memory use of raw database rows is much less - than that of an ORM-mapped object, but should still be taken into - consideration when benchmarking. - - .. seealso:: - - :ref:`engine_stream_results` + As of SQLAlchemy 1.4, the :meth:`_orm.Query.yield_per` method is + equvalent to using the ``yield_per`` execution option at the ORM level. + See the section :ref:`orm_queryguide_yield_per` for further background + on this option. """ self.load_options += {"_yield_per": count} - self._execution_options = self._execution_options.union( - {"stream_results": True, "max_row_buffer": count} - ) @util.deprecated_20( ":meth:`_orm.Query.get`", alternative="The method is now available as :meth:`_orm.Session.get`", + becomes_legacy=True, ) def get(self, ident): """Return an instance based on the given primary key identifier, @@ -983,10 +935,10 @@ class Query( def autoflush(self, setting): """Return a Query with a specific 'autoflush' setting. - Note that a Session with autoflush=False will - not autoflush, even if this flag is set to True at the - Query level. Therefore this flag is usually used only - to disable autoflush for a specific Query. + As of SQLAlchemy 1.4, the :meth:`_orm.Query.autoflush` method + is equvalent to using the ``autoflush`` execution option at the + ORM level. See the section :ref:`orm_queryguide_autoflush` for + further background on this option. """ self.load_options += {"_autoflush": setting} @@ -997,22 +949,10 @@ class Query( that will expire and refresh all instances as they are loaded, or reused from the current :class:`.Session`. - :meth:`.populate_existing` does not improve behavior when - the ORM is used normally - the :class:`.Session` object's usual - behavior of maintaining a transaction and expiring all attributes - after rollback or commit handles object state automatically. - This method is not intended for general use. - - .. versionadded:: 1.4 - - The :meth:`.populate_existing` method is equivalent to passing the - ``populate_existing=True`` option to the - :meth:`_orm.Query.execution_options` method. - - .. seealso:: - - :ref:`session_expire` - in the ORM :class:`_orm.Session` - documentation + As of SQLAlchemy 1.4, the :meth:`_orm.Query.populate_existing` method + is equvalent to using the ``populate_existing`` execution option at the + ORM level. See the section :ref:`orm_queryguide_populate_existing` for + further background on this option. """ self.load_options += {"_populate_existing": True} @@ -1031,6 +971,7 @@ class Query( @util.deprecated_20( ":meth:`_orm.Query.with_parent`", alternative="Use the :func:`_orm.with_parent` standalone construct.", + becomes_legacy=True, ) @util.preload_module("sqlalchemy.orm.relationships") def with_parent(self, instance, property=None, from_entity=None): # noqa diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index af70de101..2fc2ad68c 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -957,18 +957,8 @@ class Session(_SessionClassMethods): :ref:`session_committing` - - :param future: if True, use 2.0 style behavior for the - :meth:`_orm.Session.execute` method. Future mode includes the - following behaviors: - - * The :class:`_engine.Result` object returned by the - :meth:`_orm.Session.execute` method will return new-style tuple - :class:`_engine.Row` objects - - * The :meth:`_orm.Session.execute` method will invoke ORM style - queries given objects like :class:`_sql.Select`, - :class:`_sql.Update` and :class:`_sql.Delete` against ORM entities + :param future: if True, use 2.0 style transactional and engine + behavior. Future mode includes the following behaviors: * The :class:`_orm.Session` will not use "bound" metadata in order to locate an :class:`_engine.Engine`; the engine or engines in use @@ -984,9 +974,6 @@ class Session(_SessionClassMethods): flag on a :func:`_orm.relationship` will always assume "False" behavior. - The "future" flag is also available on a per-execution basis - using the :paramref:`_orm.Session.execute.future` flag. - .. versionadded:: 1.4 .. seealso:: @@ -1929,7 +1916,9 @@ class Session(_SessionClassMethods): def query(self, *entities, **kwargs): """Return a new :class:`_query.Query` object corresponding to this - :class:`.Session`.""" + :class:`_orm.Session`. + + """ return self._query_cls(entities, self, **kwargs) |