summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/util.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-12-11 10:34:44 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2020-12-11 11:46:48 -0500
commitc46279d1c215b7af956e40cb29afafba29d9143f (patch)
treedb93eef98b764a522dce45329b1565928ba2b903 /lib/sqlalchemy/orm/util.py
parenta15aeba4fb22503c1eb235fdc2e7a574136ca7dc (diff)
downloadsqlalchemy-c46279d1c215b7af956e40cb29afafba29d9143f.tar.gz
Revise attribute refresh for with_loader_criteria, related
Added new attribute :attr:`_orm.ORMExecuteState.is_column_load` to indicate that a :meth:`_orm.SessionEvents.do_orm_execute` handler that a particular operation is a primary-key-directed column attribute load, such as from an expiration or a deferred attribute, and that WHERE criteria or additional loader options should not be added to the query. This has been added to the examples which illustrate the :func:`_orm.with_loader_criteria` option. The :func:`_orm.with_loader_criteria` option has been modified so that it will never apply its criteria to the SELECT statement for an ORM refresh operation, such as that invoked by :meth:`_orm.Session.refresh` or whenever an expired attribute is loaded. These queries are only against the primary key row of the object that is already present in memory so there should not be additional criteria added. Added doc caveats for using lambdas. Added test coverage for most ORMExecuteState flags and fixed a few basic access issues. Change-Id: I6707e4cf0dc95cdfb8ce93e5ca22ead86074baa7 References: #5760 Fixes: #5761 Fixes: #5762
Diffstat (limited to 'lib/sqlalchemy/orm/util.py')
-rw-r--r--lib/sqlalchemy/orm/util.py42
1 files changed, 32 insertions, 10 deletions
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 886ae9a11..c9437d1b2 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -935,17 +935,38 @@ class LoaderCriteriaOption(CriteriaOption):
@event.listens_for("do_orm_execute", session)
def _add_filtering_criteria(execute_state):
- execute_state.statement = execute_state.statement.options(
- with_loader_criteria(
- SecurityRole,
- lambda cls: cls.role.in_(['some_role']),
- include_aliases=True
- )
- )
- The given class will expand to include all mapped subclass and
- need not itself be a mapped class.
+ if (
+ execute_state.is_select
+ and not execute_state.is_column_load
+ and not execute_state.is_relationship_load
+ ):
+ execute_state.statement = execute_state.statement.options(
+ with_loader_criteria(
+ SecurityRole,
+ lambda cls: cls.role.in_(['some_role']),
+ include_aliases=True
+ )
+ )
+ In the above example, the :meth:`_orm.SessionEvents.do_orm_execute`
+ event will intercept all queries emitted using the
+ :class:`_orm.Session`. For those queries which are SELECT statements
+ and are not attribute or relationship loads a custom
+ :func:`_orm.with_loader_criteria` option is added to the query. The
+ :func:`_orm.with_loader_criteria` option will be used in the given
+ statement and will also be automatically propagated to all relationship
+ loads that descend from this query.
+
+ The criteria argument given is a ``lambda`` that accepts a ``cls``
+ argument. The given class will expand to include all mapped subclass
+ and need not itself be a mapped class.
+
+ .. warning:: The use of a lambda inside of the call to
+ :func:`_orm.with_loader_criteria` is only invoked **once per unique
+ class**. Custom functions should not be invoked within this lambda.
+ See :ref:`engine_lambda_caching` for an overview of the "lambda SQL"
+ feature, which is for advanced use only.
:param entity_or_base: a mapped class, or a class that is a super
class of a particular set of mapped classes, to which the rule
@@ -1028,7 +1049,8 @@ class LoaderCriteriaOption(CriteriaOption):
# if options to limit the criteria to immediate query only,
# use compile_state.attributes instead
- self.get_global_criteria(compile_state.global_attributes)
+ if not compile_state.compile_options._for_refresh_state:
+ self.get_global_criteria(compile_state.global_attributes)
def get_global_criteria(self, attributes):
for mp in self._all_mappers():