summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/__init__.py416
-rw-r--r--lib/sqlalchemy/orm/_orm_constructors.py1557
-rw-r--r--lib/sqlalchemy/orm/base.py7
-rw-r--r--lib/sqlalchemy/orm/context.py2
-rw-r--r--lib/sqlalchemy/orm/decl_api.py2
-rw-r--r--lib/sqlalchemy/orm/decl_base.py2
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py156
-rw-r--r--lib/sqlalchemy/orm/dynamic.py4
-rw-r--r--lib/sqlalchemy/orm/interfaces.py5
-rw-r--r--lib/sqlalchemy/orm/mapper.py10
-rw-r--r--lib/sqlalchemy/orm/properties.py96
-rw-r--r--lib/sqlalchemy/orm/query.py4
-rw-r--r--lib/sqlalchemy/orm/relationships.py826
-rw-r--r--lib/sqlalchemy/orm/scoping.py2
-rw-r--r--lib/sqlalchemy/orm/util.py166
15 files changed, 1715 insertions, 1540 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 0d197bf87..17167a7de 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -13,323 +13,115 @@ documentation for an overview of how this module is used.
"""
-from . import exc
+from . import exc as exc
from . import mapper as mapperlib
-from . import strategy_options
-from .attributes import AttributeEvent
-from .attributes import InstrumentedAttribute
-from .attributes import Mapped
-from .attributes import QueryableAttribute
-from .context import QueryContext
-from .decl_api import as_declarative
-from .decl_api import declarative_base
-from .decl_api import declarative_mixin
-from .decl_api import DeclarativeMeta
-from .decl_api import declared_attr
-from .decl_api import has_inherited_table
-from .decl_api import registry
-from .decl_api import synonym_for
-from .descriptor_props import CompositeProperty
-from .descriptor_props import SynonymProperty
-from .identity import IdentityMap
-from .instrumentation import ClassManager
-from .interfaces import EXT_CONTINUE
-from .interfaces import EXT_SKIP
-from .interfaces import EXT_STOP
-from .interfaces import InspectionAttr
-from .interfaces import InspectionAttrInfo
-from .interfaces import MANYTOMANY
-from .interfaces import MANYTOONE
-from .interfaces import MapperProperty
-from .interfaces import NOT_EXTENSION
-from .interfaces import ONETOMANY
-from .interfaces import PropComparator
-from .interfaces import UserDefinedOption
-from .loading import merge_frozen_result
-from .loading import merge_result
-from .mapper import class_mapper
-from .mapper import configure_mappers
-from .mapper import Mapper
-from .mapper import reconstructor
-from .mapper import validates
-from .properties import ColumnProperty
-from .query import AliasOption
-from .query import FromStatement
-from .query import Query
-from .relationships import foreign
-from .relationships import RelationshipProperty
-from .relationships import remote
-from .scoping import scoped_session
-from .session import close_all_sessions
-from .session import make_transient
-from .session import make_transient_to_detached
-from .session import object_session
-from .session import ORMExecuteState
-from .session import Session
-from .session import sessionmaker
-from .session import SessionTransaction
-from .state import AttributeState
-from .state import InstanceState
-from .strategy_options import contains_eager
-from .strategy_options import defaultload
-from .strategy_options import defer
-from .strategy_options import immediateload
-from .strategy_options import joinedload
-from .strategy_options import lazyload
-from .strategy_options import Load
-from .strategy_options import load_only
-from .strategy_options import noload
-from .strategy_options import raiseload
-from .strategy_options import selectin_polymorphic
-from .strategy_options import selectinload
-from .strategy_options import subqueryload
-from .strategy_options import undefer
-from .strategy_options import undefer_group
-from .strategy_options import with_expression
-from .unitofwork import UOWTransaction
-from .util import aliased
-from .util import Bundle
-from .util import CascadeOptions
-from .util import join
-from .util import LoaderCriteriaOption
-from .util import object_mapper
-from .util import outerjoin
-from .util import polymorphic_union
-from .util import was_deleted
-from .util import with_parent
-from .util import with_polymorphic
-from .. import sql as _sql
+from . import strategy_options as strategy_options
+from ._orm_constructors import _mapper_fn as mapper
+from ._orm_constructors import backref as backref
+from ._orm_constructors import clear_mappers as clear_mappers
+from ._orm_constructors import column_property as column_property
+from ._orm_constructors import composite as composite
+from ._orm_constructors import contains_alias as contains_alias
+from ._orm_constructors import create_session as create_session
+from ._orm_constructors import deferred as deferred
+from ._orm_constructors import dynamic_loader as dynamic_loader
+from ._orm_constructors import query_expression as query_expression
+from ._orm_constructors import relationship as relationship
+from ._orm_constructors import synonym as synonym
+from ._orm_constructors import with_loader_criteria as with_loader_criteria
+from .attributes import AttributeEvent as AttributeEvent
+from .attributes import InstrumentedAttribute as InstrumentedAttribute
+from .attributes import Mapped as Mapped
+from .attributes import QueryableAttribute as QueryableAttribute
+from .context import QueryContext as QueryContext
+from .decl_api import as_declarative as as_declarative
+from .decl_api import declarative_base as declarative_base
+from .decl_api import declarative_mixin as declarative_mixin
+from .decl_api import DeclarativeMeta as DeclarativeMeta
+from .decl_api import declared_attr as declared_attr
+from .decl_api import has_inherited_table as has_inherited_table
+from .decl_api import registry as registry
+from .decl_api import synonym_for as synonym_for
+from .descriptor_props import CompositeProperty as CompositeProperty
+from .descriptor_props import SynonymProperty as SynonymProperty
+from .dynamic import AppenderQuery as AppenderQuery
+from .events import AttributeEvents as AttributeEvents
+from .events import InstanceEvents as InstanceEvents
+from .events import InstrumentationEvents as InstrumentationEvents
+from .events import MapperEvents as MapperEvents
+from .events import QueryEvents as QueryEvents
+from .events import SessionEvents as SessionEvents
+from .identity import IdentityMap as IdentityMap
+from .instrumentation import ClassManager as ClassManager
+from .interfaces import EXT_CONTINUE as EXT_CONTINUE
+from .interfaces import EXT_SKIP as EXT_SKIP
+from .interfaces import EXT_STOP as EXT_STOP
+from .interfaces import InspectionAttr as InspectionAttr
+from .interfaces import InspectionAttrInfo as InspectionAttrInfo
+from .interfaces import MANYTOMANY as MANYTOMANY
+from .interfaces import MANYTOONE as MANYTOONE
+from .interfaces import MapperProperty as MapperProperty
+from .interfaces import NOT_EXTENSION as NOT_EXTENSION
+from .interfaces import ONETOMANY as ONETOMANY
+from .interfaces import PropComparator as PropComparator
+from .interfaces import UserDefinedOption as UserDefinedOption
+from .loading import merge_frozen_result as merge_frozen_result
+from .loading import merge_result as merge_result
+from .mapper import class_mapper as class_mapper
+from .mapper import configure_mappers as configure_mappers
+from .mapper import Mapper as Mapper
+from .mapper import reconstructor as reconstructor
+from .mapper import validates as validates
+from .properties import ColumnProperty as ColumnProperty
+from .query import AliasOption as AliasOption
+from .query import FromStatement as FromStatement
+from .query import Query as Query
+from .relationships import foreign as foreign
+from .relationships import RelationshipProperty as RelationshipProperty
+from .relationships import remote as remote
+from .scoping import scoped_session as scoped_session
+from .session import close_all_sessions as close_all_sessions
+from .session import make_transient as make_transient
+from .session import make_transient_to_detached as make_transient_to_detached
+from .session import object_session as object_session
+from .session import ORMExecuteState as ORMExecuteState
+from .session import Session as Session
+from .session import sessionmaker as sessionmaker
+from .session import SessionTransaction as SessionTransaction
+from .state import AttributeState as AttributeState
+from .state import InstanceState as InstanceState
+from .strategy_options import contains_eager as contains_eager
+from .strategy_options import defaultload as defaultload
+from .strategy_options import defer as defer
+from .strategy_options import immediateload as immediateload
+from .strategy_options import joinedload as joinedload
+from .strategy_options import lazyload as lazyload
+from .strategy_options import Load as Load
+from .strategy_options import load_only as load_only
+from .strategy_options import noload as noload
+from .strategy_options import raiseload as raiseload
+from .strategy_options import selectin_polymorphic as selectin_polymorphic
+from .strategy_options import selectinload as selectinload
+from .strategy_options import subqueryload as subqueryload
+from .strategy_options import undefer as undefer
+from .strategy_options import undefer_group as undefer_group
+from .strategy_options import with_expression as with_expression
+from .unitofwork import UOWTransaction as UOWTransaction
+from .util import aliased as aliased
+from .util import Bundle as Bundle
+from .util import CascadeOptions as CascadeOptions
+from .util import join as join
+from .util import LoaderCriteriaOption as LoaderCriteriaOption
+from .util import object_mapper as object_mapper
+from .util import outerjoin as outerjoin
+from .util import polymorphic_union as polymorphic_union
+from .util import was_deleted as was_deleted
+from .util import with_parent as with_parent
+from .util import with_polymorphic as with_polymorphic
from .. import util as _sa_util
-from ..exc import InvalidRequestError
-from ..util.langhelpers import public_factory
-
-
-def create_session(bind=None, **kwargs):
- r"""Create a new :class:`.Session`
- with no automation enabled by default.
-
- This function is used primarily for testing. The usual
- route to :class:`.Session` creation is via its constructor
- or the :func:`.sessionmaker` function.
-
- :param bind: optional, a single Connectable to use for all
- database access in the created
- :class:`~sqlalchemy.orm.session.Session`.
-
- :param \*\*kwargs: optional, passed through to the
- :class:`.Session` constructor.
-
- :returns: an :class:`~sqlalchemy.orm.session.Session` instance
-
- The defaults of create_session() are the opposite of that of
- :func:`sessionmaker`; ``autoflush`` and ``expire_on_commit`` are
- False.
-
- Usage::
-
- >>> from sqlalchemy.orm import create_session
- >>> session = create_session()
-
- It is recommended to use :func:`sessionmaker` instead of
- create_session().
-
- """
-
- kwargs.setdefault("autoflush", False)
- kwargs.setdefault("expire_on_commit", False)
- return Session(bind=bind, **kwargs)
-
-
-with_loader_criteria = public_factory(LoaderCriteriaOption, ".orm")
-
-relationship = public_factory(RelationshipProperty, ".orm.relationship")
-
-
-def mapper(*arg, **kw):
- """Placeholder for the now-removed ``mapper()`` function.
-
- Classical mappings should be performed using the
- :meth:`_orm.registry.map_imperatively` method.
-
- This symbol remains in SQLAlchemy 2.0 to suit the deprecated use case
- of using the ``mapper()`` function as a target for ORM event listeners,
- which failed to be marked as deprecated in the 1.4 series.
-
- Global ORM mapper listeners should instead use the :class:`_orm.Mapper`
- class as the target.
-
- .. versionchanged:: 2.0 The ``mapper()`` function was removed; the
- symbol remains temporarily as a placeholder for the event listening
- use case.
-
- """
- raise InvalidRequestError(
- "The 'sqlalchemy.orm.mapper()' function is removed as of "
- "SQLAlchemy 2.0. Use the "
- "'sqlalchemy.orm.registry.map_imperatively()` "
- "method of the ``sqlalchemy.orm.registry`` class to perform "
- "classical mapping."
- )
-
-
-def dynamic_loader(argument, **kw):
- """Construct a dynamically-loading mapper property.
-
- This is essentially the same as
- using the ``lazy='dynamic'`` argument with :func:`relationship`::
-
- dynamic_loader(SomeClass)
-
- # is the same as
-
- relationship(SomeClass, lazy="dynamic")
-
- See the section :ref:`dynamic_relationship` for more details
- on dynamic loading.
-
- """
- kw["lazy"] = "dynamic"
- return relationship(argument, **kw)
-
-
-column_property = public_factory(ColumnProperty, ".orm.column_property")
-composite = public_factory(CompositeProperty, ".orm.composite")
-
-
-def backref(name, **kwargs):
- """Create a back reference with explicit keyword arguments, which are the
- same arguments one can send to :func:`relationship`.
-
- Used with the ``backref`` keyword argument to :func:`relationship` in
- place of a string argument, e.g.::
-
- 'items':relationship(
- SomeItem, backref=backref('parent', lazy='subquery'))
-
- .. seealso::
-
- :ref:`relationships_backref`
-
- """
-
- return (name, kwargs)
-
-
-def deferred(*columns, **kw):
- r"""Indicate a column-based mapped attribute that by default will
- not load unless accessed.
-
- :param \*columns: columns to be mapped. This is typically a single
- :class:`_schema.Column` object,
- however a collection is supported in order
- to support multiple columns mapped under the same attribute.
-
- :param raiseload: boolean, if True, indicates an exception should be raised
- if the load operation is to take place.
-
- .. versionadded:: 1.4
-
- .. seealso::
-
- :ref:`deferred_raiseload`
-
- :param \**kw: additional keyword arguments passed to
- :class:`.ColumnProperty`.
-
- .. seealso::
-
- :ref:`deferred`
-
- """
- return ColumnProperty(deferred=True, *columns, **kw)
-
-
-def query_expression(default_expr=_sql.null()):
- """Indicate an attribute that populates from a query-time SQL expression.
-
- :param default_expr: Optional SQL expression object that will be used in
- all cases if not assigned later with :func:`_orm.with_expression`.
- E.g.::
-
- from sqlalchemy.sql import literal
-
- class C(Base):
- #...
- my_expr = query_expression(literal(1))
-
- .. versionadded:: 1.3.18
-
-
- .. versionadded:: 1.2
-
- .. seealso::
-
- :ref:`mapper_querytime_expression`
-
- """
- prop = ColumnProperty(default_expr)
- prop.strategy_key = (("query_expression", True),)
- return prop
-
-
-synonym = public_factory(SynonymProperty, ".orm.synonym")
-
-
-def clear_mappers():
- """Remove all mappers from all classes.
-
- .. versionchanged:: 1.4 This function now locates all
- :class:`_orm.registry` objects and calls upon the
- :meth:`_orm.registry.dispose` method of each.
-
- This function removes all instrumentation from classes and disposes
- of their associated mappers. Once called, the classes are unmapped
- and can be later re-mapped with new mappers.
-
- :func:`.clear_mappers` is *not* for normal use, as there is literally no
- valid usage for it outside of very specific testing scenarios. Normally,
- mappers are permanent structural components of user-defined classes, and
- are never discarded independently of their class. If a mapped class
- itself is garbage collected, its mapper is automatically disposed of as
- well. As such, :func:`.clear_mappers` is only for usage in test suites
- that re-use the same classes with different mappings, which is itself an
- extremely rare use case - the only such use case is in fact SQLAlchemy's
- own test suite, and possibly the test suites of other ORM extension
- libraries which intend to test various combinations of mapper construction
- upon a fixed set of classes.
-
- """
-
- mapperlib._dispose_registries(mapperlib._all_registries(), False)
-
-
-contains_alias = public_factory(AliasOption, ".orm.contains_alias")
-
-if True:
- from .events import AttributeEvents
- from .events import MapperEvents
- from .events import InstanceEvents
- from .events import InstrumentationEvents
- from .events import QueryEvents
- from .events import SessionEvents
def __go(lcls):
- global __all__
- global AppenderQuery
- from .. import util as sa_util
- from . import dynamic
- from . import events
- from . import loading
- import inspect as _inspect
-
- from .dynamic import AppenderQuery
-
- __all__ = sorted(
- name
- for name, obj in lcls.items()
- if not (name.startswith("_") or _inspect.ismodule(obj))
- )
_sa_util.preloaded.import_prefix("sqlalchemy.orm")
_sa_util.preloaded.import_prefix("sqlalchemy.ext")
diff --git a/lib/sqlalchemy/orm/_orm_constructors.py b/lib/sqlalchemy/orm/_orm_constructors.py
new file mode 100644
index 000000000..be0d23d00
--- /dev/null
+++ b/lib/sqlalchemy/orm/_orm_constructors.py
@@ -0,0 +1,1557 @@
+# orm/_orm_constructors.py
+# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
+# <see AUTHORS file>
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: https://www.opensource.org/licenses/mit-license.php
+
+import typing
+from typing import Callable
+from typing import Type
+from typing import Union
+
+from . import mapper as mapperlib
+from .descriptor_props import CompositeProperty
+from .descriptor_props import SynonymProperty
+from .properties import ColumnProperty
+from .query import AliasOption
+from .relationships import RelationshipProperty
+from .session import Session
+from .util import LoaderCriteriaOption
+from .. import sql
+from .. import util
+from ..exc import InvalidRequestError
+
+_RC = typing.TypeVar("_RC")
+_T = typing.TypeVar("_T")
+
+
+@util.deprecated(
+ "1.4",
+ "The :class:`.AliasOption` object is not necessary "
+ "for entities to be matched up to a query that is established "
+ "via :meth:`.Query.from_statement` and now does nothing.",
+)
+def contains_alias(alias) -> "AliasOption":
+ r"""Return a :class:`.MapperOption` that will indicate to the
+ :class:`_query.Query`
+ that the main table has been aliased.
+
+ """
+ return AliasOption(alias)
+
+
+def column_property(
+ column: sql.ColumnElement[_T], *additional_columns, **kwargs
+) -> "ColumnProperty[_T]":
+ r"""Provide a column-level property for use with a mapping.
+
+ Column-based properties can normally be applied to the mapper's
+ ``properties`` dictionary using the :class:`_schema.Column`
+ element directly.
+ Use this function when the given column is not directly present within
+ the mapper's selectable; examples include SQL expressions, functions,
+ and scalar SELECT queries.
+
+ The :func:`_orm.column_property` function returns an instance of
+ :class:`.ColumnProperty`.
+
+ Columns that aren't present in the mapper's selectable won't be
+ persisted by the mapper and are effectively "read-only" attributes.
+
+ :param \*cols:
+ list of Column objects to be mapped.
+
+ :param active_history=False:
+ When ``True``, indicates that the "previous" value for a
+ scalar attribute should be loaded when replaced, if not
+ already loaded. Normally, history tracking logic for
+ simple non-primary-key scalar values only needs to be
+ aware of the "new" value in order to perform a flush. This
+ flag is available for applications that make use of
+ :func:`.attributes.get_history` or :meth:`.Session.is_modified`
+ which also need to know
+ the "previous" value of the attribute.
+
+ :param comparator_factory: a class which extends
+ :class:`.ColumnProperty.Comparator` which provides custom SQL
+ clause generation for comparison operations.
+
+ :param group:
+ a group name for this property when marked as deferred.
+
+ :param deferred:
+ when True, the column property is "deferred", meaning that
+ it does not load immediately, and is instead loaded when the
+ attribute is first accessed on an instance. See also
+ :func:`~sqlalchemy.orm.deferred`.
+
+ :param doc:
+ optional string that will be applied as the doc on the
+ class-bound descriptor.
+
+ :param expire_on_flush=True:
+ Disable expiry on flush. A column_property() which refers
+ to a SQL expression (and not a single table-bound column)
+ is considered to be a "read only" property; populating it
+ has no effect on the state of data, and it can only return
+ database state. For this reason a column_property()'s value
+ is expired whenever the parent object is involved in a
+ flush, that is, has any kind of "dirty" state within a flush.
+ Setting this parameter to ``False`` will have the effect of
+ leaving any existing value present after the flush proceeds.
+ Note however that the :class:`.Session` with default expiration
+ settings still expires
+ all attributes after a :meth:`.Session.commit` call, however.
+
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.MapperProperty.info` attribute of this object.
+
+ :param raiseload: if True, indicates the column should raise an error
+ when undeferred, rather than loading the value. This can be
+ altered at query time by using the :func:`.deferred` option with
+ raiseload=False.
+
+ .. versionadded:: 1.4
+
+ .. seealso::
+
+ :ref:`deferred_raiseload`
+
+ .. seealso::
+
+ :ref:`column_property_options` - to map columns while including
+ mapping options
+
+ :ref:`mapper_column_property_sql_expressions` - to map SQL
+ expressions
+
+ """
+ return ColumnProperty(column, *additional_columns, **kwargs)
+
+
+def composite(class_: Type[_T], *attrs, **kwargs) -> "CompositeProperty[_T]":
+ r"""Return a composite column-based property for use with a Mapper.
+
+ See the mapping documentation section :ref:`mapper_composite` for a
+ full usage example.
+
+ The :class:`.MapperProperty` returned by :func:`.composite`
+ is the :class:`.CompositeProperty`.
+
+ :param class\_:
+ The "composite type" class, or any classmethod or callable which
+ will produce a new instance of the composite object given the
+ column values in order.
+
+ :param \*cols:
+ List of Column objects to be mapped.
+
+ :param active_history=False:
+ When ``True``, indicates that the "previous" value for a
+ scalar attribute should be loaded when replaced, if not
+ already loaded. See the same flag on :func:`.column_property`.
+
+ :param group:
+ A group name for this property when marked as deferred.
+
+ :param deferred:
+ When True, the column property is "deferred", meaning that it does
+ not load immediately, and is instead loaded when the attribute is
+ first accessed on an instance. See also
+ :func:`~sqlalchemy.orm.deferred`.
+
+ :param comparator_factory: a class which extends
+ :class:`.CompositeProperty.Comparator` which provides custom SQL
+ clause generation for comparison operations.
+
+ :param doc:
+ optional string that will be applied as the doc on the
+ class-bound descriptor.
+
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.MapperProperty.info` attribute of this object.
+
+ """
+ return CompositeProperty(class_, *attrs, **kwargs)
+
+
+def with_loader_criteria(
+ entity_or_base,
+ where_criteria,
+ loader_only=False,
+ include_aliases=False,
+ propagate_to_loaders=True,
+ track_closure_variables=True,
+) -> "LoaderCriteriaOption":
+ """Add additional WHERE criteria to the load for all occurrences of
+ a particular entity.
+
+ .. versionadded:: 1.4
+
+ The :func:`_orm.with_loader_criteria` option is intended to add
+ limiting criteria to a particular kind of entity in a query,
+ **globally**, meaning it will apply to the entity as it appears
+ in the SELECT query as well as within any subqueries, join
+ conditions, and relationship loads, including both eager and lazy
+ loaders, without the need for it to be specified in any particular
+ part of the query. The rendering logic uses the same system used by
+ single table inheritance to ensure a certain discriminator is applied
+ to a table.
+
+ E.g., using :term:`2.0-style` queries, we can limit the way the
+ ``User.addresses`` collection is loaded, regardless of the kind
+ of loading used::
+
+ from sqlalchemy.orm import with_loader_criteria
+
+ stmt = select(User).options(
+ selectinload(User.addresses),
+ with_loader_criteria(Address, Address.email_address != 'foo'))
+ )
+
+ Above, the "selectinload" for ``User.addresses`` will apply the
+ given filtering criteria to the WHERE clause.
+
+ Another example, where the filtering will be applied to the
+ ON clause of the join, in this example using :term:`1.x style`
+ queries::
+
+ q = session.query(User).outerjoin(User.addresses).options(
+ with_loader_criteria(Address, Address.email_address != 'foo'))
+ )
+
+ The primary purpose of :func:`_orm.with_loader_criteria` is to use
+ it in the :meth:`_orm.SessionEvents.do_orm_execute` event handler
+ to ensure that all occurrences of a particular entity are filtered
+ in a certain way, such as filtering for access control roles. It
+ also can be used to apply criteria to relationship loads. In the
+ example below, we can apply a certain set of rules to all queries
+ emitted by a particular :class:`_orm.Session`::
+
+ session = Session(bind=engine)
+
+ @event.listens_for("do_orm_execute", session)
+ def _add_filtering_criteria(execute_state):
+
+ 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.
+
+ .. tip::
+
+ When using :func:`_orm.with_loader_criteria` option in
+ conjunction with the :func:`_orm.contains_eager` loader option,
+ it's important to note that :func:`_orm.with_loader_criteria` only
+ affects the part of the query that determines what SQL is rendered
+ in terms of the WHERE and FROM clauses. The
+ :func:`_orm.contains_eager` option does not affect the rendering of
+ the SELECT statement outside of the columns clause, so does not have
+ any interaction with the :func:`_orm.with_loader_criteria` option.
+ However, the way things "work" is that :func:`_orm.contains_eager`
+ is meant to be used with a query that is already selecting from the
+ additional entities in some way, where
+ :func:`_orm.with_loader_criteria` can apply it's additional
+ criteria.
+
+ In the example below, assuming a mapping relationship as
+ ``A -> A.bs -> B``, the given :func:`_orm.with_loader_criteria`
+ option will affect the way in which the JOIN is rendered::
+
+ stmt = select(A).join(A.bs).options(
+ contains_eager(A.bs),
+ with_loader_criteria(B, B.flag == 1)
+ )
+
+ Above, the given :func:`_orm.with_loader_criteria` option will
+ affect the ON clause of the JOIN that is specified by
+ ``.join(A.bs)``, so is applied as expected. The
+ :func:`_orm.contains_eager` option has the effect that columns from
+ ``B`` are added to the columns clause::
+
+ SELECT
+ b.id, b.a_id, b.data, b.flag,
+ a.id AS id_1,
+ a.data AS data_1
+ FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
+
+
+ The use of the :func:`_orm.contains_eager` option within the above
+ statement has no effect on the behavior of the
+ :func:`_orm.with_loader_criteria` option. If the
+ :func:`_orm.contains_eager` option were omitted, the SQL would be
+ the same as regards the FROM and WHERE clauses, where
+ :func:`_orm.with_loader_criteria` continues to add its criteria to
+ the ON clause of the JOIN. The addition of
+ :func:`_orm.contains_eager` only affects the columns clause, in that
+ additional columns against ``b`` are added which are then consumed
+ by the ORM to produce ``B`` instances.
+
+ .. 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
+ will apply.
+
+ :param where_criteria: a Core SQL expression that applies limiting
+ criteria. This may also be a "lambda:" or Python function that
+ accepts a target class as an argument, when the given class is
+ a base with many different mapped subclasses.
+
+ :param include_aliases: if True, apply the rule to :func:`_orm.aliased`
+ constructs as well.
+
+ :param propagate_to_loaders: defaults to True, apply to relationship
+ loaders such as lazy loaders.
+
+
+ .. seealso::
+
+ :ref:`examples_session_orm_events` - includes examples of using
+ :func:`_orm.with_loader_criteria`.
+
+ :ref:`do_orm_execute_global_criteria` - basic example on how to
+ combine :func:`_orm.with_loader_criteria` with the
+ :meth:`_orm.SessionEvents.do_orm_execute` event.
+
+ :param track_closure_variables: when False, closure variables inside
+ of a lambda expression will not be used as part of
+ any cache key. This allows more complex expressions to be used
+ inside of a lambda expression but requires that the lambda ensures
+ it returns the identical SQL every time given a particular class.
+
+ .. versionadded:: 1.4.0b2
+
+ """
+ return LoaderCriteriaOption(
+ entity_or_base,
+ where_criteria,
+ loader_only,
+ include_aliases,
+ propagate_to_loaders,
+ track_closure_variables,
+ )
+
+
+def relationship(
+ argument: Union[str, Type[_RC], Callable[[], Type[_RC]]],
+ secondary=None,
+ primaryjoin=None,
+ secondaryjoin=None,
+ foreign_keys=None,
+ uselist=None,
+ order_by=False,
+ backref=None,
+ back_populates=None,
+ overlaps=None,
+ post_update=False,
+ cascade=False,
+ viewonly=False,
+ lazy="select",
+ collection_class=None,
+ passive_deletes=RelationshipProperty._persistence_only["passive_deletes"],
+ passive_updates=RelationshipProperty._persistence_only["passive_updates"],
+ remote_side=None,
+ enable_typechecks=RelationshipProperty._persistence_only[
+ "enable_typechecks"
+ ],
+ join_depth=None,
+ comparator_factory=None,
+ single_parent=False,
+ innerjoin=False,
+ distinct_target_key=None,
+ doc=None,
+ active_history=RelationshipProperty._persistence_only["active_history"],
+ cascade_backrefs=RelationshipProperty._persistence_only[
+ "cascade_backrefs"
+ ],
+ load_on_pending=False,
+ bake_queries=True,
+ _local_remote_pairs=None,
+ query_class=None,
+ info=None,
+ omit_join=None,
+ sync_backref=None,
+ _legacy_inactive_history_style=False,
+) -> RelationshipProperty[_RC]:
+ """Provide a relationship between two mapped classes.
+
+ This corresponds to a parent-child or associative table relationship.
+ The constructed class is an instance of
+ :class:`.RelationshipProperty`.
+
+ A typical :func:`_orm.relationship`, used in a classical mapping::
+
+ mapper(Parent, properties={
+ 'children': relationship(Child)
+ })
+
+ Some arguments accepted by :func:`_orm.relationship`
+ optionally accept a
+ callable function, which when called produces the desired value.
+ The callable is invoked by the parent :class:`_orm.Mapper` at "mapper
+ initialization" time, which happens only when mappers are first used,
+ and is assumed to be after all mappings have been constructed. This
+ can be used to resolve order-of-declaration and other dependency
+ issues, such as if ``Child`` is declared below ``Parent`` in the same
+ file::
+
+ mapper(Parent, properties={
+ "children":relationship(lambda: Child,
+ order_by=lambda: Child.id)
+ })
+
+ When using the :ref:`declarative_toplevel` extension, the Declarative
+ initializer allows string arguments to be passed to
+ :func:`_orm.relationship`. These string arguments are converted into
+ callables that evaluate the string as Python code, using the
+ Declarative class-registry as a namespace. This allows the lookup of
+ related classes to be automatic via their string name, and removes the
+ need for related classes to be imported into the local module space
+ before the dependent classes have been declared. It is still required
+ that the modules in which these related classes appear are imported
+ anywhere in the application at some point before the related mappings
+ are actually used, else a lookup error will be raised when the
+ :func:`_orm.relationship`
+ attempts to resolve the string reference to the
+ related class. An example of a string- resolved class is as
+ follows::
+
+ from sqlalchemy.ext.declarative import declarative_base
+
+ Base = declarative_base()
+
+ class Parent(Base):
+ __tablename__ = 'parent'
+ id = Column(Integer, primary_key=True)
+ children = relationship("Child", order_by="Child.id")
+
+ .. seealso::
+
+ :ref:`relationship_config_toplevel` - Full introductory and
+ reference documentation for :func:`_orm.relationship`.
+
+ :ref:`orm_tutorial_relationship` - ORM tutorial introduction.
+
+ :param argument:
+ A mapped class, or actual :class:`_orm.Mapper` instance,
+ representing
+ the target of the relationship.
+
+ :paramref:`_orm.relationship.argument`
+ may also be passed as a callable
+ function which is evaluated at mapper initialization time, and may
+ be passed as a string name when using Declarative.
+
+ .. warning:: Prior to SQLAlchemy 1.3.16, this value is interpreted
+ using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ .. versionchanged 1.3.16::
+
+ The string evaluation of the main "argument" no longer accepts an
+ open ended Python expression, instead only accepting a string
+ class name or dotted package-qualified name.
+
+ .. seealso::
+
+ :ref:`declarative_configuring_relationships` - further detail
+ on relationship configuration when using Declarative.
+
+ :param secondary:
+ For a many-to-many relationship, specifies the intermediary
+ table, and is typically an instance of :class:`_schema.Table`.
+ In less common circumstances, the argument may also be specified
+ as an :class:`_expression.Alias` construct, or even a
+ :class:`_expression.Join` construct.
+
+ :paramref:`_orm.relationship.secondary` may
+ also be passed as a callable function which is evaluated at
+ mapper initialization time. When using Declarative, it may also
+ be a string argument noting the name of a :class:`_schema.Table`
+ that is
+ present in the :class:`_schema.MetaData`
+ collection associated with the
+ parent-mapped :class:`_schema.Table`.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ The :paramref:`_orm.relationship.secondary` keyword argument is
+ typically applied in the case where the intermediary
+ :class:`_schema.Table`
+ is not otherwise expressed in any direct class mapping. If the
+ "secondary" table is also explicitly mapped elsewhere (e.g. as in
+ :ref:`association_pattern`), one should consider applying the
+ :paramref:`_orm.relationship.viewonly` flag so that this
+ :func:`_orm.relationship`
+ is not used for persistence operations which
+ may conflict with those of the association object pattern.
+
+ .. seealso::
+
+ :ref:`relationships_many_to_many` - Reference example of "many
+ to many".
+
+ :ref:`orm_tutorial_many_to_many` - ORM tutorial introduction to
+ many-to-many relationships.
+
+ :ref:`self_referential_many_to_many` - Specifics on using
+ many-to-many in a self-referential case.
+
+ :ref:`declarative_many_to_many` - Additional options when using
+ Declarative.
+
+ :ref:`association_pattern` - an alternative to
+ :paramref:`_orm.relationship.secondary`
+ when composing association
+ table relationships, allowing additional attributes to be
+ specified on the association table.
+
+ :ref:`composite_secondary_join` - a lesser-used pattern which
+ in some cases can enable complex :func:`_orm.relationship` SQL
+ conditions to be used.
+
+ .. versionadded:: 0.9.2 :paramref:`_orm.relationship.secondary`
+ works
+ more effectively when referring to a :class:`_expression.Join`
+ instance.
+
+ :param active_history=False:
+ When ``True``, indicates that the "previous" value for a
+ many-to-one reference should be loaded when replaced, if
+ not already loaded. Normally, history tracking logic for
+ simple many-to-ones only needs to be aware of the "new"
+ value in order to perform a flush. This flag is available
+ for applications that make use of
+ :func:`.attributes.get_history` which also need to know
+ the "previous" value of the attribute.
+
+ :param backref:
+ Indicates the string name of a property to be placed on the related
+ mapper's class that will handle this relationship in the other
+ direction. The other property will be created automatically
+ when the mappers are configured. Can also be passed as a
+ :func:`.backref` object to control the configuration of the
+ new relationship.
+
+ .. seealso::
+
+ :ref:`relationships_backref` - Introductory documentation and
+ examples.
+
+ :paramref:`_orm.relationship.back_populates` - alternative form
+ of backref specification.
+
+ :func:`.backref` - allows control over :func:`_orm.relationship`
+ configuration when using :paramref:`_orm.relationship.backref`.
+
+
+ :param back_populates:
+ Takes a string name and has the same meaning as
+ :paramref:`_orm.relationship.backref`, except the complementing
+ property is **not** created automatically, and instead must be
+ configured explicitly on the other mapper. The complementing
+ property should also indicate
+ :paramref:`_orm.relationship.back_populates` to this relationship to
+ ensure proper functioning.
+
+ .. seealso::
+
+ :ref:`relationships_backref` - Introductory documentation and
+ examples.
+
+ :paramref:`_orm.relationship.backref` - alternative form
+ of backref specification.
+
+ :param overlaps:
+ A string name or comma-delimited set of names of other relationships
+ on either this mapper, a descendant mapper, or a target mapper with
+ which this relationship may write to the same foreign keys upon
+ persistence. The only effect this has is to eliminate the
+ warning that this relationship will conflict with another upon
+ persistence. This is used for such relationships that are truly
+ capable of conflicting with each other on write, but the application
+ will ensure that no such conflicts occur.
+
+ .. versionadded:: 1.4
+
+ .. seealso::
+
+ :ref:`error_qzyx` - usage example
+
+ :param bake_queries=True:
+ Enable :ref:`lambda caching <engine_lambda_caching>` for loader
+ strategies, if applicable, which adds a performance gain to the
+ construction of SQL constructs used by loader strategies, in addition
+ to the usual SQL statement caching used throughout SQLAlchemy. This
+ parameter currently applies only to the "lazy" and "selectin" loader
+ strategies. There is generally no reason to set this parameter to
+ False.
+
+ .. versionchanged:: 1.4 Relationship loaders no longer use the
+ previous "baked query" system of query caching. The "lazy"
+ and "selectin" loaders make use of the "lambda cache" system
+ for the construction of SQL constructs,
+ as well as the usual SQL caching system that is throughout
+ SQLAlchemy as of the 1.4 series.
+
+ :param cascade:
+ A comma-separated list of cascade rules which determines how
+ Session operations should be "cascaded" from parent to child.
+ This defaults to ``False``, which means the default cascade
+ should be used - this default cascade is ``"save-update, merge"``.
+
+ The available cascades are ``save-update``, ``merge``,
+ ``expunge``, ``delete``, ``delete-orphan``, and ``refresh-expire``.
+ An additional option, ``all`` indicates shorthand for
+ ``"save-update, merge, refresh-expire,
+ expunge, delete"``, and is often used as in ``"all, delete-orphan"``
+ to indicate that related objects should follow along with the
+ parent object in all cases, and be deleted when de-associated.
+
+ .. seealso::
+
+ :ref:`unitofwork_cascades` - Full detail on each of the available
+ cascade options.
+
+ :ref:`tutorial_delete_cascade` - Tutorial example describing
+ a delete cascade.
+
+ :param cascade_backrefs=False:
+ Legacy; this flag is always False.
+
+ .. versionchanged:: 2.0 "cascade_backrefs" functionality has been
+ removed.
+
+ :param collection_class:
+ A class or callable that returns a new list-holding object. will
+ be used in place of a plain list for storing elements.
+
+ .. seealso::
+
+ :ref:`custom_collections` - Introductory documentation and
+ examples.
+
+ :param comparator_factory:
+ A class which extends :class:`.RelationshipProperty.Comparator`
+ which provides custom SQL clause generation for comparison
+ operations.
+
+ .. seealso::
+
+ :class:`.PropComparator` - some detail on redefining comparators
+ at this level.
+
+ :ref:`custom_comparators` - Brief intro to this feature.
+
+
+ :param distinct_target_key=None:
+ Indicate if a "subquery" eager load should apply the DISTINCT
+ keyword to the innermost SELECT statement. When left as ``None``,
+ the DISTINCT keyword will be applied in those cases when the target
+ columns do not comprise the full primary key of the target table.
+ When set to ``True``, the DISTINCT keyword is applied to the
+ innermost SELECT unconditionally.
+
+ It may be desirable to set this flag to False when the DISTINCT is
+ reducing performance of the innermost subquery beyond that of what
+ duplicate innermost rows may be causing.
+
+ .. versionchanged:: 0.9.0 -
+ :paramref:`_orm.relationship.distinct_target_key` now defaults to
+ ``None``, so that the feature enables itself automatically for
+ those cases where the innermost query targets a non-unique
+ key.
+
+ .. seealso::
+
+ :ref:`loading_toplevel` - includes an introduction to subquery
+ eager loading.
+
+ :param doc:
+ Docstring which will be applied to the resulting descriptor.
+
+ :param foreign_keys:
+
+ A list of columns which are to be used as "foreign key"
+ columns, or columns which refer to the value in a remote
+ column, within the context of this :func:`_orm.relationship`
+ object's :paramref:`_orm.relationship.primaryjoin` condition.
+ That is, if the :paramref:`_orm.relationship.primaryjoin`
+ condition of this :func:`_orm.relationship` is ``a.id ==
+ b.a_id``, and the values in ``b.a_id`` are required to be
+ present in ``a.id``, then the "foreign key" column of this
+ :func:`_orm.relationship` is ``b.a_id``.
+
+ In normal cases, the :paramref:`_orm.relationship.foreign_keys`
+ parameter is **not required.** :func:`_orm.relationship` will
+ automatically determine which columns in the
+ :paramref:`_orm.relationship.primaryjoin` condition are to be
+ considered "foreign key" columns based on those
+ :class:`_schema.Column` objects that specify
+ :class:`_schema.ForeignKey`,
+ or are otherwise listed as referencing columns in a
+ :class:`_schema.ForeignKeyConstraint` construct.
+ :paramref:`_orm.relationship.foreign_keys` is only needed when:
+
+ 1. There is more than one way to construct a join from the local
+ table to the remote table, as there are multiple foreign key
+ references present. Setting ``foreign_keys`` will limit the
+ :func:`_orm.relationship`
+ to consider just those columns specified
+ here as "foreign".
+
+ 2. The :class:`_schema.Table` being mapped does not actually have
+ :class:`_schema.ForeignKey` or
+ :class:`_schema.ForeignKeyConstraint`
+ constructs present, often because the table
+ was reflected from a database that does not support foreign key
+ reflection (MySQL MyISAM).
+
+ 3. The :paramref:`_orm.relationship.primaryjoin`
+ argument is used to
+ construct a non-standard join condition, which makes use of
+ columns or expressions that do not normally refer to their
+ "parent" column, such as a join condition expressed by a
+ complex comparison using a SQL function.
+
+ The :func:`_orm.relationship` construct will raise informative
+ error messages that suggest the use of the
+ :paramref:`_orm.relationship.foreign_keys` parameter when
+ presented with an ambiguous condition. In typical cases,
+ if :func:`_orm.relationship` doesn't raise any exceptions, the
+ :paramref:`_orm.relationship.foreign_keys` parameter is usually
+ not needed.
+
+ :paramref:`_orm.relationship.foreign_keys` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ .. seealso::
+
+ :ref:`relationship_foreign_keys`
+
+ :ref:`relationship_custom_foreign`
+
+ :func:`.foreign` - allows direct annotation of the "foreign"
+ columns within a :paramref:`_orm.relationship.primaryjoin`
+ condition.
+
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.MapperProperty.info` attribute of this object.
+
+ :param innerjoin=False:
+ When ``True``, joined eager loads will use an inner join to join
+ against related tables instead of an outer join. The purpose
+ of this option is generally one of performance, as inner joins
+ generally perform better than outer joins.
+
+ This flag can be set to ``True`` when the relationship references an
+ object via many-to-one using local foreign keys that are not
+ nullable, or when the reference is one-to-one or a collection that
+ is guaranteed to have one or at least one entry.
+
+ The option supports the same "nested" and "unnested" options as
+ that of :paramref:`_orm.joinedload.innerjoin`. See that flag
+ for details on nested / unnested behaviors.
+
+ .. seealso::
+
+ :paramref:`_orm.joinedload.innerjoin` - the option as specified by
+ loader option, including detail on nesting behavior.
+
+ :ref:`what_kind_of_loading` - Discussion of some details of
+ various loader options.
+
+
+ :param join_depth:
+ When non-``None``, an integer value indicating how many levels
+ deep "eager" loaders should join on a self-referring or cyclical
+ relationship. The number counts how many times the same Mapper
+ shall be present in the loading condition along a particular join
+ branch. When left at its default of ``None``, eager loaders
+ will stop chaining when they encounter a the same target mapper
+ which is already higher up in the chain. This option applies
+ both to joined- and subquery- eager loaders.
+
+ .. seealso::
+
+ :ref:`self_referential_eager_loading` - Introductory documentation
+ and examples.
+
+ :param lazy='select': specifies
+ How the related items should be loaded. Default value is
+ ``select``. Values include:
+
+ * ``select`` - items should be loaded lazily when the property is
+ first accessed, using a separate SELECT statement, or identity map
+ fetch for simple many-to-one references.
+
+ * ``immediate`` - items should be loaded as the parents are loaded,
+ using a separate SELECT statement, or identity map fetch for
+ simple many-to-one references.
+
+ * ``joined`` - items should be loaded "eagerly" in the same query as
+ that of the parent, using a JOIN or LEFT OUTER JOIN. Whether
+ the join is "outer" or not is determined by the
+ :paramref:`_orm.relationship.innerjoin` parameter.
+
+ * ``subquery`` - items should be loaded "eagerly" as the parents are
+ loaded, using one additional SQL statement, which issues a JOIN to
+ a subquery of the original statement, for each collection
+ requested.
+
+ * ``selectin`` - items should be loaded "eagerly" as the parents
+ are loaded, using one or more additional SQL statements, which
+ issues a JOIN to the immediate parent object, specifying primary
+ key identifiers using an IN clause.
+
+ .. versionadded:: 1.2
+
+ * ``noload`` - no loading should occur at any time. This is to
+ support "write-only" attributes, or attributes which are
+ populated in some manner specific to the application.
+
+ * ``raise`` - lazy loading is disallowed; accessing
+ the attribute, if its value were not already loaded via eager
+ loading, will raise an :exc:`~sqlalchemy.exc.InvalidRequestError`.
+ This strategy can be used when objects are to be detached from
+ their attached :class:`.Session` after they are loaded.
+
+ .. versionadded:: 1.1
+
+ * ``raise_on_sql`` - lazy loading that emits SQL is disallowed;
+ accessing the attribute, if its value were not already loaded via
+ eager loading, will raise an
+ :exc:`~sqlalchemy.exc.InvalidRequestError`, **if the lazy load
+ needs to emit SQL**. If the lazy load can pull the related value
+ from the identity map or determine that it should be None, the
+ value is loaded. This strategy can be used when objects will
+ remain associated with the attached :class:`.Session`, however
+ additional SELECT statements should be blocked.
+
+ .. versionadded:: 1.1
+
+ * ``dynamic`` - the attribute will return a pre-configured
+ :class:`_query.Query` object for all read
+ operations, onto which further filtering operations can be
+ applied before iterating the results. See
+ the section :ref:`dynamic_relationship` for more details.
+
+ * True - a synonym for 'select'
+
+ * False - a synonym for 'joined'
+
+ * None - a synonym for 'noload'
+
+ .. seealso::
+
+ :doc:`/orm/loading_relationships` - Full documentation on
+ relationship loader configuration.
+
+ :ref:`dynamic_relationship` - detail on the ``dynamic`` option.
+
+ :ref:`collections_noload_raiseload` - notes on "noload" and "raise"
+
+ :param load_on_pending=False:
+ Indicates loading behavior for transient or pending parent objects.
+
+ When set to ``True``, causes the lazy-loader to
+ issue a query for a parent object that is not persistent, meaning it
+ has never been flushed. This may take effect for a pending object
+ when autoflush is disabled, or for a transient object that has been
+ "attached" to a :class:`.Session` but is not part of its pending
+ collection.
+
+ The :paramref:`_orm.relationship.load_on_pending`
+ flag does not improve
+ behavior when the ORM is used normally - object references should be
+ constructed at the object level, not at the foreign key level, so
+ that they are present in an ordinary way before a flush proceeds.
+ This flag is not not intended for general use.
+
+ .. seealso::
+
+ :meth:`.Session.enable_relationship_loading` - this method
+ establishes "load on pending" behavior for the whole object, and
+ also allows loading on objects that remain transient or
+ detached.
+
+ :param order_by:
+ Indicates the ordering that should be applied when loading these
+ items. :paramref:`_orm.relationship.order_by`
+ is expected to refer to
+ one of the :class:`_schema.Column`
+ objects to which the target class is
+ mapped, or the attribute itself bound to the target class which
+ refers to the column.
+
+ :paramref:`_orm.relationship.order_by`
+ may also be passed as a callable
+ function which is evaluated at mapper initialization time, and may
+ be passed as a Python-evaluable string when using Declarative.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ :param passive_deletes=False:
+ Indicates loading behavior during delete operations.
+
+ A value of True indicates that unloaded child items should not
+ be loaded during a delete operation on the parent. Normally,
+ when a parent item is deleted, all child items are loaded so
+ that they can either be marked as deleted, or have their
+ foreign key to the parent set to NULL. Marking this flag as
+ True usually implies an ON DELETE <CASCADE|SET NULL> rule is in
+ place which will handle updating/deleting child rows on the
+ database side.
+
+ Additionally, setting the flag to the string value 'all' will
+ disable the "nulling out" of the child foreign keys, when the parent
+ object is deleted and there is no delete or delete-orphan cascade
+ enabled. This is typically used when a triggering or error raise
+ scenario is in place on the database side. Note that the foreign
+ key attributes on in-session child objects will not be changed after
+ a flush occurs so this is a very special use-case setting.
+ Additionally, the "nulling out" will still occur if the child
+ object is de-associated with the parent.
+
+ .. seealso::
+
+ :ref:`passive_deletes` - Introductory documentation
+ and examples.
+
+ :param passive_updates=True:
+ Indicates the persistence behavior to take when a referenced
+ primary key value changes in place, indicating that the referencing
+ foreign key columns will also need their value changed.
+
+ When True, it is assumed that ``ON UPDATE CASCADE`` is configured on
+ the foreign key in the database, and that the database will
+ handle propagation of an UPDATE from a source column to
+ dependent rows. When False, the SQLAlchemy
+ :func:`_orm.relationship`
+ construct will attempt to emit its own UPDATE statements to
+ modify related targets. However note that SQLAlchemy **cannot**
+ emit an UPDATE for more than one level of cascade. Also,
+ setting this flag to False is not compatible in the case where
+ the database is in fact enforcing referential integrity, unless
+ those constraints are explicitly "deferred", if the target backend
+ supports it.
+
+ It is highly advised that an application which is employing
+ mutable primary keys keeps ``passive_updates`` set to True,
+ and instead uses the referential integrity features of the database
+ itself in order to handle the change efficiently and fully.
+
+ .. seealso::
+
+ :ref:`passive_updates` - Introductory documentation and
+ examples.
+
+ :paramref:`.mapper.passive_updates` - a similar flag which
+ takes effect for joined-table inheritance mappings.
+
+ :param post_update:
+ This indicates that the relationship should be handled by a
+ second UPDATE statement after an INSERT or before a
+ DELETE. Currently, it also will issue an UPDATE after the
+ instance was UPDATEd as well, although this technically should
+ be improved. This flag is used to handle saving bi-directional
+ dependencies between two individual rows (i.e. each row
+ references the other), where it would otherwise be impossible to
+ INSERT or DELETE both rows fully since one row exists before the
+ other. Use this flag when a particular mapping arrangement will
+ incur two rows that are dependent on each other, such as a table
+ that has a one-to-many relationship to a set of child rows, and
+ also has a column that references a single child row within that
+ list (i.e. both tables contain a foreign key to each other). If
+ a flush operation returns an error that a "cyclical
+ dependency" was detected, this is a cue that you might want to
+ use :paramref:`_orm.relationship.post_update` to "break" the cycle.
+
+ .. seealso::
+
+ :ref:`post_update` - Introductory documentation and examples.
+
+ :param primaryjoin:
+ A SQL expression that will be used as the primary
+ join of the child object against the parent object, or in a
+ many-to-many relationship the join of the parent object to the
+ association table. By default, this value is computed based on the
+ foreign key relationships of the parent and child tables (or
+ association table).
+
+ :paramref:`_orm.relationship.primaryjoin` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ .. seealso::
+
+ :ref:`relationship_primaryjoin`
+
+ :param remote_side:
+ Used for self-referential relationships, indicates the column or
+ list of columns that form the "remote side" of the relationship.
+
+ :paramref:`_orm.relationship.remote_side` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ .. seealso::
+
+ :ref:`self_referential` - in-depth explanation of how
+ :paramref:`_orm.relationship.remote_side`
+ is used to configure self-referential relationships.
+
+ :func:`.remote` - an annotation function that accomplishes the
+ same purpose as :paramref:`_orm.relationship.remote_side`,
+ typically
+ when a custom :paramref:`_orm.relationship.primaryjoin` condition
+ is used.
+
+ :param query_class:
+ A :class:`_query.Query`
+ subclass that will be used internally by the
+ ``AppenderQuery`` returned by a "dynamic" relationship, that
+ is, a relationship that specifies ``lazy="dynamic"`` or was
+ otherwise constructed using the :func:`_orm.dynamic_loader`
+ function.
+
+ .. seealso::
+
+ :ref:`dynamic_relationship` - Introduction to "dynamic"
+ relationship loaders.
+
+ :param secondaryjoin:
+ A SQL expression that will be used as the join of
+ an association table to the child object. By default, this value is
+ computed based on the foreign key relationships of the association
+ and child tables.
+
+ :paramref:`_orm.relationship.secondaryjoin` may also be passed as a
+ callable function which is evaluated at mapper initialization time,
+ and may be passed as a Python-evaluable string when using
+ Declarative.
+
+ .. warning:: When passed as a Python-evaluable string, the
+ argument is interpreted using Python's ``eval()`` function.
+ **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+ See :ref:`declarative_relationship_eval` for details on
+ declarative evaluation of :func:`_orm.relationship` arguments.
+
+ .. seealso::
+
+ :ref:`relationship_primaryjoin`
+
+ :param single_parent:
+ When True, installs a validator which will prevent objects
+ from being associated with more than one parent at a time.
+ This is used for many-to-one or many-to-many relationships that
+ should be treated either as one-to-one or one-to-many. Its usage
+ is optional, except for :func:`_orm.relationship` constructs which
+ are many-to-one or many-to-many and also
+ specify the ``delete-orphan`` cascade option. The
+ :func:`_orm.relationship` construct itself will raise an error
+ instructing when this option is required.
+
+ .. seealso::
+
+ :ref:`unitofwork_cascades` - includes detail on when the
+ :paramref:`_orm.relationship.single_parent`
+ flag may be appropriate.
+
+ :param uselist:
+ A boolean that indicates if this property should be loaded as a
+ list or a scalar. In most cases, this value is determined
+ automatically by :func:`_orm.relationship` at mapper configuration
+ time, based on the type and direction
+ of the relationship - one to many forms a list, many to one
+ forms a scalar, many to many is a list. If a scalar is desired
+ where normally a list would be present, such as a bi-directional
+ one-to-one relationship, set :paramref:`_orm.relationship.uselist`
+ to
+ False.
+
+ The :paramref:`_orm.relationship.uselist`
+ flag is also available on an
+ existing :func:`_orm.relationship`
+ construct as a read-only attribute,
+ which can be used to determine if this :func:`_orm.relationship`
+ deals
+ with collections or scalar attributes::
+
+ >>> User.addresses.property.uselist
+ True
+
+ .. seealso::
+
+ :ref:`relationships_one_to_one` - Introduction to the "one to
+ one" relationship pattern, which is typically when the
+ :paramref:`_orm.relationship.uselist` flag is needed.
+
+ :param viewonly=False:
+ When set to ``True``, the relationship is used only for loading
+ objects, and not for any persistence operation. A
+ :func:`_orm.relationship` which specifies
+ :paramref:`_orm.relationship.viewonly` can work
+ with a wider range of SQL operations within the
+ :paramref:`_orm.relationship.primaryjoin` condition, including
+ operations that feature the use of a variety of comparison operators
+ as well as SQL functions such as :func:`_expression.cast`. The
+ :paramref:`_orm.relationship.viewonly`
+ flag is also of general use when defining any kind of
+ :func:`_orm.relationship` that doesn't represent
+ the full set of related objects, to prevent modifications of the
+ collection from resulting in persistence operations.
+
+ When using the :paramref:`_orm.relationship.viewonly` flag in
+ conjunction with backrefs, the originating relationship for a
+ particular state change will not produce state changes within the
+ viewonly relationship. This is the behavior implied by
+ :paramref:`_orm.relationship.sync_backref` being set to False.
+
+ .. versionchanged:: 1.3.17 - the
+ :paramref:`_orm.relationship.sync_backref` flag is set to False
+ when using viewonly in conjunction with backrefs.
+
+ .. seealso::
+
+ :paramref:`_orm.relationship.sync_backref`
+
+ :param sync_backref:
+ A boolean that enables the events used to synchronize the in-Python
+ attributes when this relationship is target of either
+ :paramref:`_orm.relationship.backref` or
+ :paramref:`_orm.relationship.back_populates`.
+
+ Defaults to ``None``, which indicates that an automatic value should
+ be selected based on the value of the
+ :paramref:`_orm.relationship.viewonly` flag. When left at its
+ default, changes in state will be back-populated only if neither
+ sides of a relationship is viewonly.
+
+ .. versionadded:: 1.3.17
+
+ .. versionchanged:: 1.4 - A relationship that specifies
+ :paramref:`_orm.relationship.viewonly` automatically implies
+ that :paramref:`_orm.relationship.sync_backref` is ``False``.
+
+ .. seealso::
+
+ :paramref:`_orm.relationship.viewonly`
+
+ :param omit_join:
+ Allows manual control over the "selectin" automatic join
+ optimization. Set to ``False`` to disable the "omit join" feature
+ added in SQLAlchemy 1.3; or leave as ``None`` to leave automatic
+ optimization in place.
+
+ .. note:: This flag may only be set to ``False``. It is not
+ necessary to set it to ``True`` as the "omit_join" optimization is
+ automatically detected; if it is not detected, then the
+ optimization is not supported.
+
+ .. versionchanged:: 1.3.11 setting ``omit_join`` to True will now
+ emit a warning as this was not the intended use of this flag.
+
+ .. versionadded:: 1.3
+
+
+ """
+ return RelationshipProperty(
+ argument,
+ secondary,
+ primaryjoin,
+ secondaryjoin,
+ foreign_keys,
+ uselist,
+ order_by,
+ backref,
+ back_populates,
+ overlaps,
+ post_update,
+ cascade,
+ viewonly,
+ lazy,
+ collection_class,
+ passive_deletes,
+ passive_updates,
+ remote_side,
+ enable_typechecks,
+ join_depth,
+ comparator_factory,
+ single_parent,
+ innerjoin,
+ distinct_target_key,
+ doc,
+ active_history,
+ cascade_backrefs,
+ load_on_pending,
+ bake_queries,
+ _local_remote_pairs,
+ query_class,
+ info,
+ omit_join,
+ sync_backref,
+ _legacy_inactive_history_style,
+ )
+
+
+def synonym(
+ name,
+ map_column=None,
+ descriptor=None,
+ comparator_factory=None,
+ doc=None,
+ info=None,
+) -> "SynonymProperty":
+ """Denote an attribute name as a synonym to a mapped property,
+ in that the attribute will mirror the value and expression behavior
+ of another attribute.
+
+ e.g.::
+
+ class MyClass(Base):
+ __tablename__ = 'my_table'
+
+ id = Column(Integer, primary_key=True)
+ job_status = Column(String(50))
+
+ status = synonym("job_status")
+
+
+ :param name: the name of the existing mapped property. This
+ can refer to the string name ORM-mapped attribute
+ configured on the class, including column-bound attributes
+ and relationships.
+
+ :param descriptor: a Python :term:`descriptor` that will be used
+ as a getter (and potentially a setter) when this attribute is
+ accessed at the instance level.
+
+ :param map_column: **For classical mappings and mappings against
+ an existing Table object only**. if ``True``, the :func:`.synonym`
+ construct will locate the :class:`_schema.Column`
+ object upon the mapped
+ table that would normally be associated with the attribute name of
+ this synonym, and produce a new :class:`.ColumnProperty` that instead
+ maps this :class:`_schema.Column`
+ to the alternate name given as the "name"
+ argument of the synonym; in this way, the usual step of redefining
+ the mapping of the :class:`_schema.Column`
+ to be under a different name is
+ unnecessary. This is usually intended to be used when a
+ :class:`_schema.Column`
+ is to be replaced with an attribute that also uses a
+ descriptor, that is, in conjunction with the
+ :paramref:`.synonym.descriptor` parameter::
+
+ my_table = Table(
+ "my_table", metadata,
+ Column('id', Integer, primary_key=True),
+ Column('job_status', String(50))
+ )
+
+ class MyClass:
+ @property
+ def _job_status_descriptor(self):
+ return "Status: %s" % self._job_status
+
+
+ mapper(
+ MyClass, my_table, properties={
+ "job_status": synonym(
+ "_job_status", map_column=True,
+ descriptor=MyClass._job_status_descriptor)
+ }
+ )
+
+ Above, the attribute named ``_job_status`` is automatically
+ mapped to the ``job_status`` column::
+
+ >>> j1 = MyClass()
+ >>> j1._job_status = "employed"
+ >>> j1.job_status
+ Status: employed
+
+ When using Declarative, in order to provide a descriptor in
+ conjunction with a synonym, use the
+ :func:`sqlalchemy.ext.declarative.synonym_for` helper. However,
+ note that the :ref:`hybrid properties <mapper_hybrids>` feature
+ should usually be preferred, particularly when redefining attribute
+ behavior.
+
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.InspectionAttr.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
+ :param comparator_factory: A subclass of :class:`.PropComparator`
+ that will provide custom comparison behavior at the SQL expression
+ level.
+
+ .. note::
+
+ For the use case of providing an attribute which redefines both
+ Python-level and SQL-expression level behavior of an attribute,
+ please refer to the Hybrid attribute introduced at
+ :ref:`mapper_hybrids` for a more effective technique.
+
+ .. seealso::
+
+ :ref:`synonyms` - Overview of synonyms
+
+ :func:`.synonym_for` - a helper oriented towards Declarative
+
+ :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
+ updated approach to augmenting attribute behavior more flexibly
+ than can be achieved with synonyms.
+
+ """
+ return SynonymProperty(
+ name, map_column, descriptor, comparator_factory, doc, info
+ )
+
+
+def create_session(bind=None, **kwargs):
+ r"""Create a new :class:`.Session`
+ with no automation enabled by default.
+
+ This function is used primarily for testing. The usual
+ route to :class:`.Session` creation is via its constructor
+ or the :func:`.sessionmaker` function.
+
+ :param bind: optional, a single Connectable to use for all
+ database access in the created
+ :class:`~sqlalchemy.orm.session.Session`.
+
+ :param \*\*kwargs: optional, passed through to the
+ :class:`.Session` constructor.
+
+ :returns: an :class:`~sqlalchemy.orm.session.Session` instance
+
+ The defaults of create_session() are the opposite of that of
+ :func:`sessionmaker`; ``autoflush`` and ``expire_on_commit`` are
+ False.
+
+ Usage::
+
+ >>> from sqlalchemy.orm import create_session
+ >>> session = create_session()
+
+ It is recommended to use :func:`sessionmaker` instead of
+ create_session().
+
+ """
+
+ kwargs.setdefault("autoflush", False)
+ kwargs.setdefault("expire_on_commit", False)
+ return Session(bind=bind, **kwargs)
+
+
+def _mapper_fn(*arg, **kw):
+ """Placeholder for the now-removed ``mapper()`` function.
+
+ Classical mappings should be performed using the
+ :meth:`_orm.registry.map_imperatively` method.
+
+ This symbol remains in SQLAlchemy 2.0 to suit the deprecated use case
+ of using the ``mapper()`` function as a target for ORM event listeners,
+ which failed to be marked as deprecated in the 1.4 series.
+
+ Global ORM mapper listeners should instead use the :class:`_orm.Mapper`
+ class as the target.
+
+ .. versionchanged:: 2.0 The ``mapper()`` function was removed; the
+ symbol remains temporarily as a placeholder for the event listening
+ use case.
+
+ """
+ raise InvalidRequestError(
+ "The 'sqlalchemy.orm.mapper()' function is removed as of "
+ "SQLAlchemy 2.0. Use the "
+ "'sqlalchemy.orm.registry.map_imperatively()` "
+ "method of the ``sqlalchemy.orm.registry`` class to perform "
+ "classical mapping."
+ )
+
+
+def dynamic_loader(argument, **kw):
+ """Construct a dynamically-loading mapper property.
+
+ This is essentially the same as
+ using the ``lazy='dynamic'`` argument with :func:`relationship`::
+
+ dynamic_loader(SomeClass)
+
+ # is the same as
+
+ relationship(SomeClass, lazy="dynamic")
+
+ See the section :ref:`dynamic_relationship` for more details
+ on dynamic loading.
+
+ """
+ kw["lazy"] = "dynamic"
+ return relationship(argument, **kw)
+
+
+def backref(name, **kwargs):
+ """Create a back reference with explicit keyword arguments, which are the
+ same arguments one can send to :func:`relationship`.
+
+ Used with the ``backref`` keyword argument to :func:`relationship` in
+ place of a string argument, e.g.::
+
+ 'items':relationship(
+ SomeItem, backref=backref('parent', lazy='subquery'))
+
+ .. seealso::
+
+ :ref:`relationships_backref`
+
+ """
+
+ return (name, kwargs)
+
+
+def deferred(*columns, **kw):
+ r"""Indicate a column-based mapped attribute that by default will
+ not load unless accessed.
+
+ :param \*columns: columns to be mapped. This is typically a single
+ :class:`_schema.Column` object,
+ however a collection is supported in order
+ to support multiple columns mapped under the same attribute.
+
+ :param raiseload: boolean, if True, indicates an exception should be raised
+ if the load operation is to take place.
+
+ .. versionadded:: 1.4
+
+ .. seealso::
+
+ :ref:`deferred_raiseload`
+
+ :param \**kw: additional keyword arguments passed to
+ :class:`.ColumnProperty`.
+
+ .. seealso::
+
+ :ref:`deferred`
+
+ """
+ return ColumnProperty(deferred=True, *columns, **kw)
+
+
+def query_expression(default_expr=sql.null()):
+ """Indicate an attribute that populates from a query-time SQL expression.
+
+ :param default_expr: Optional SQL expression object that will be used in
+ all cases if not assigned later with :func:`_orm.with_expression`.
+ E.g.::
+
+ from sqlalchemy.sql import literal
+
+ class C(Base):
+ #...
+ my_expr = query_expression(literal(1))
+
+ .. versionadded:: 1.3.18
+
+
+ .. versionadded:: 1.2
+
+ .. seealso::
+
+ :ref:`mapper_querytime_expression`
+
+ """
+ prop = ColumnProperty(default_expr)
+ prop.strategy_key = (("query_expression", True),)
+ return prop
+
+
+def clear_mappers():
+ """Remove all mappers from all classes.
+
+ .. versionchanged:: 1.4 This function now locates all
+ :class:`_orm.registry` objects and calls upon the
+ :meth:`_orm.registry.dispose` method of each.
+
+ This function removes all instrumentation from classes and disposes
+ of their associated mappers. Once called, the classes are unmapped
+ and can be later re-mapped with new mappers.
+
+ :func:`.clear_mappers` is *not* for normal use, as there is literally no
+ valid usage for it outside of very specific testing scenarios. Normally,
+ mappers are permanent structural components of user-defined classes, and
+ are never discarded independently of their class. If a mapped class
+ itself is garbage collected, its mapper is automatically disposed of as
+ well. As such, :func:`.clear_mappers` is only for usage in test suites
+ that re-use the same classes with different mappings, which is itself an
+ extremely rare use case - the only such use case is in fact SQLAlchemy's
+ own test suite, and possibly the test suites of other ORM extension
+ libraries which intend to test various combinations of mapper construction
+ upon a fixed set of classes.
+
+ """
+
+ mapperlib._dispose_registries(mapperlib._all_registries(), False)
diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py
index 10902e970..93e2d609a 100644
--- a/lib/sqlalchemy/orm/base.py
+++ b/lib/sqlalchemy/orm/base.py
@@ -11,6 +11,9 @@
import operator
import typing
+from typing import Any
+from typing import Generic
+from typing import TypeVar
from . import exc
from .. import exc as sa_exc
@@ -19,6 +22,8 @@ from .. import util
from ..util import typing as compat_typing
+_T = TypeVar("_T", bound=Any)
+
PASSIVE_NO_RESULT = util.symbol(
"PASSIVE_NO_RESULT",
"""Symbol returned by a loader callable or other attribute/history
@@ -574,7 +579,7 @@ class InspectionAttrInfo(InspectionAttr):
return {}
-class _MappedAttribute:
+class _MappedAttribute(Generic[_T]):
"""Mixin for attributes which should be replaced by mapper-assigned
attributes.
diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py
index cba7cf07d..e8ac892ce 100644
--- a/lib/sqlalchemy/orm/context.py
+++ b/lib/sqlalchemy/orm/context.py
@@ -34,6 +34,7 @@ from ..sql.base import Options
from ..sql.selectable import LABEL_STYLE_DISAMBIGUATE_ONLY
from ..sql.selectable import LABEL_STYLE_NONE
from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
+from ..sql.selectable import Select
from ..sql.selectable import SelectState
from ..sql.visitors import InternalTraversal
@@ -1132,7 +1133,6 @@ class ORMSelectCompileState(ORMCompileState, SelectState):
group_by,
):
- Select = future.Select
statement = Select._create_raw_select(
_raw_columns=raw_columns,
_from_obj=from_obj,
diff --git a/lib/sqlalchemy/orm/decl_api.py b/lib/sqlalchemy/orm/decl_api.py
index 2a5b1bb2b..99b2e9b6f 100644
--- a/lib/sqlalchemy/orm/decl_api.py
+++ b/lib/sqlalchemy/orm/decl_api.py
@@ -14,7 +14,7 @@ from . import clsregistry
from . import exc as orm_exc
from . import instrumentation
from . import interfaces
-from . import mapper as mapperlib
+from . import mapperlib
from .base import _inspect_mapped_class
from .decl_base import _add_attribute
from .decl_base import _as_declarative
diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py
index 4316271f0..fb736806c 100644
--- a/lib/sqlalchemy/orm/decl_base.py
+++ b/lib/sqlalchemy/orm/decl_base.py
@@ -12,7 +12,7 @@ from sqlalchemy.orm import attributes
from sqlalchemy.orm import instrumentation
from . import clsregistry
from . import exc as orm_exc
-from . import mapper as mapperlib
+from . import mapperlib
from .attributes import InstrumentedAttribute
from .attributes import QueryableAttribute
from .base import _is_mapped_class
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index d5083dcf1..80fce86d0 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -10,6 +10,9 @@ that exist as configurational elements, but don't participate
as actively in the load/persist ORM loop.
"""
+from typing import Any
+from typing import Type
+from typing import TypeVar
from . import attributes
from . import util as orm_util
@@ -24,8 +27,10 @@ from .. import util
from ..sql import expression
from ..sql import operators
+_T = TypeVar("_T", bound=Any)
-class DescriptorProperty(MapperProperty):
+
+class DescriptorProperty(MapperProperty[_T]):
""":class:`.MapperProperty` which proxies access to a
user-defined descriptor."""
@@ -86,7 +91,7 @@ class DescriptorProperty(MapperProperty):
mapper.class_manager.instrument_attribute(self.key, proxy_attr)
-class CompositeProperty(DescriptorProperty):
+class CompositeProperty(DescriptorProperty[_T]):
"""Defines a "composite" mapped attribute, representing a collection
of columns as one attribute.
@@ -99,49 +104,7 @@ class CompositeProperty(DescriptorProperty):
"""
- def __init__(self, class_, *attrs, **kwargs):
- r"""Return a composite column-based property for use with a Mapper.
-
- See the mapping documentation section :ref:`mapper_composite` for a
- full usage example.
-
- The :class:`.MapperProperty` returned by :func:`.composite`
- is the :class:`.CompositeProperty`.
-
- :param class\_:
- The "composite type" class, or any classmethod or callable which
- will produce a new instance of the composite object given the
- column values in order.
-
- :param \*cols:
- List of Column objects to be mapped.
-
- :param active_history=False:
- When ``True``, indicates that the "previous" value for a
- scalar attribute should be loaded when replaced, if not
- already loaded. See the same flag on :func:`.column_property`.
-
- :param group:
- A group name for this property when marked as deferred.
-
- :param deferred:
- When True, the column property is "deferred", meaning that it does
- not load immediately, and is instead loaded when the attribute is
- first accessed on an instance. See also
- :func:`~sqlalchemy.orm.deferred`.
-
- :param comparator_factory: a class which extends
- :class:`.CompositeProperty.Comparator` which provides custom SQL
- clause generation for comparison operations.
-
- :param doc:
- optional string that will be applied as the doc on the
- class-bound descriptor.
-
- :param info: Optional data dictionary which will be populated into the
- :attr:`.MapperProperty.info` attribute of this object.
-
- """
+ def __init__(self, class_: Type[_T], *attrs, **kwargs):
super(CompositeProperty, self).__init__()
self.attrs = attrs
@@ -548,109 +511,6 @@ class SynonymProperty(DescriptorProperty):
doc=None,
info=None,
):
- """Denote an attribute name as a synonym to a mapped property,
- in that the attribute will mirror the value and expression behavior
- of another attribute.
-
- e.g.::
-
- class MyClass(Base):
- __tablename__ = 'my_table'
-
- id = Column(Integer, primary_key=True)
- job_status = Column(String(50))
-
- status = synonym("job_status")
-
-
- :param name: the name of the existing mapped property. This
- can refer to the string name ORM-mapped attribute
- configured on the class, including column-bound attributes
- and relationships.
-
- :param descriptor: a Python :term:`descriptor` that will be used
- as a getter (and potentially a setter) when this attribute is
- accessed at the instance level.
-
- :param map_column: **For classical mappings and mappings against
- an existing Table object only**. if ``True``, the :func:`.synonym`
- construct will locate the :class:`_schema.Column`
- object upon the mapped
- table that would normally be associated with the attribute name of
- this synonym, and produce a new :class:`.ColumnProperty` that instead
- maps this :class:`_schema.Column`
- to the alternate name given as the "name"
- argument of the synonym; in this way, the usual step of redefining
- the mapping of the :class:`_schema.Column`
- to be under a different name is
- unnecessary. This is usually intended to be used when a
- :class:`_schema.Column`
- is to be replaced with an attribute that also uses a
- descriptor, that is, in conjunction with the
- :paramref:`.synonym.descriptor` parameter::
-
- my_table = Table(
- "my_table", metadata,
- Column('id', Integer, primary_key=True),
- Column('job_status', String(50))
- )
-
- class MyClass:
- @property
- def _job_status_descriptor(self):
- return "Status: %s" % self._job_status
-
-
- mapper(
- MyClass, my_table, properties={
- "job_status": synonym(
- "_job_status", map_column=True,
- descriptor=MyClass._job_status_descriptor)
- }
- )
-
- Above, the attribute named ``_job_status`` is automatically
- mapped to the ``job_status`` column::
-
- >>> j1 = MyClass()
- >>> j1._job_status = "employed"
- >>> j1.job_status
- Status: employed
-
- When using Declarative, in order to provide a descriptor in
- conjunction with a synonym, use the
- :func:`sqlalchemy.ext.declarative.synonym_for` helper. However,
- note that the :ref:`hybrid properties <mapper_hybrids>` feature
- should usually be preferred, particularly when redefining attribute
- behavior.
-
- :param info: Optional data dictionary which will be populated into the
- :attr:`.InspectionAttr.info` attribute of this object.
-
- .. versionadded:: 1.0.0
-
- :param comparator_factory: A subclass of :class:`.PropComparator`
- that will provide custom comparison behavior at the SQL expression
- level.
-
- .. note::
-
- For the use case of providing an attribute which redefines both
- Python-level and SQL-expression level behavior of an attribute,
- please refer to the Hybrid attribute introduced at
- :ref:`mapper_hybrids` for a more effective technique.
-
- .. seealso::
-
- :ref:`synonyms` - Overview of synonyms
-
- :func:`.synonym_for` - a helper oriented towards Declarative
-
- :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
- updated approach to augmenting attribute behavior more flexibly
- than can be achieved with synonyms.
-
- """
super(SynonymProperty, self).__init__()
self.name = name
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py
index 7b2be9f05..ade47480d 100644
--- a/lib/sqlalchemy/orm/dynamic.py
+++ b/lib/sqlalchemy/orm/dynamic.py
@@ -15,12 +15,12 @@ basic add/delete mutation.
from . import attributes
from . import exc as orm_exc
from . import interfaces
-from . import object_mapper
-from . import object_session
from . import relationships
from . import strategies
from . import util as orm_util
+from .base import object_mapper
from .query import Query
+from .session import object_session
from .. import exc
from .. import log
from .. import util
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index d842df221..df265db57 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -17,6 +17,8 @@ are exposed when inspecting mappings.
"""
import collections
+from typing import Any
+from typing import TypeVar
from . import exc as orm_exc
from . import path_registry
@@ -39,6 +41,7 @@ from ..sql import visitors
from ..sql.base import ExecutableOption
from ..sql.cache_key import HasCacheKey
+_T = TypeVar("_T", bound=Any)
__all__ = (
"EXT_CONTINUE",
@@ -77,7 +80,7 @@ class ORMFromClauseRole(roles.StrictFromClauseRole):
@inspection._self_inspects
class MapperProperty(
- HasCacheKey, _MappedAttribute, InspectionAttr, util.MemoizedSlots
+ HasCacheKey, _MappedAttribute[_T], InspectionAttr, util.MemoizedSlots
):
"""Represent a particular class attribute mapped by :class:`_orm.Mapper`.
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index dbcbc8a1b..87829d643 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -14,11 +14,13 @@ This is a semi-private module; the main configurational API of the ORM is
available in :class:`~sqlalchemy.orm.`.
"""
-
from collections import deque
from functools import reduce
from itertools import chain
import sys
+from typing import Generic
+from typing import Type
+from typing import TypeVar
import weakref
from . import attributes
@@ -58,6 +60,9 @@ from ..util import HasMemoized
_mapper_registries = weakref.WeakKeyDictionary()
+_MC = TypeVar("_MC")
+
+
def _all_registries():
with _CONFIGURE_MUTEX:
return set(_mapper_registries)
@@ -88,6 +93,7 @@ class Mapper(
ORMEntityColumnsClauseRole,
sql_base.MemoizedHasCacheKey,
InspectionAttr,
+ Generic[_MC],
):
"""Defines an association between a Python class and a database table or
other relational structure, so that ORM operations against the class may
@@ -115,7 +121,7 @@ class Mapper(
)
def __init__(
self,
- class_,
+ class_: Type[_MC],
local_table=None,
properties=None,
primary_key=None,
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 1fd5dbaf8..8ee26315e 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -12,6 +12,10 @@ mapped attributes.
"""
+from typing import Any
+from typing import Generic
+from typing import TypeVar
+
from . import attributes
from . import strategy_options
from .descriptor_props import CompositeProperty
@@ -22,10 +26,12 @@ from .interfaces import StrategizedProperty
from .relationships import RelationshipProperty
from .util import _orm_full_deannotate
from .. import log
+from .. import sql
from .. import util
from ..sql import coercions
from ..sql import roles
+_T = TypeVar("_T", bound=Any)
__all__ = [
"ColumnProperty",
@@ -37,7 +43,7 @@ __all__ = [
@log.class_logger
-class ColumnProperty(StrategizedProperty):
+class ColumnProperty(StrategizedProperty, Generic[_T]):
"""Describes an object attribute that corresponds to a table column.
Public constructor is the :func:`_orm.column_property` function.
@@ -70,91 +76,11 @@ class ColumnProperty(StrategizedProperty):
"raiseload",
)
- def __init__(self, *columns, **kwargs):
- r"""Provide a column-level property for use with a mapping.
-
- Column-based properties can normally be applied to the mapper's
- ``properties`` dictionary using the :class:`_schema.Column`
- element directly.
- Use this function when the given column is not directly present within
- the mapper's selectable; examples include SQL expressions, functions,
- and scalar SELECT queries.
-
- The :func:`_orm.column_property` function returns an instance of
- :class:`.ColumnProperty`.
-
- Columns that aren't present in the mapper's selectable won't be
- persisted by the mapper and are effectively "read-only" attributes.
-
- :param \*cols:
- list of Column objects to be mapped.
-
- :param active_history=False:
- When ``True``, indicates that the "previous" value for a
- scalar attribute should be loaded when replaced, if not
- already loaded. Normally, history tracking logic for
- simple non-primary-key scalar values only needs to be
- aware of the "new" value in order to perform a flush. This
- flag is available for applications that make use of
- :func:`.attributes.get_history` or :meth:`.Session.is_modified`
- which also need to know
- the "previous" value of the attribute.
-
- :param comparator_factory: a class which extends
- :class:`.ColumnProperty.Comparator` which provides custom SQL
- clause generation for comparison operations.
-
- :param group:
- a group name for this property when marked as deferred.
-
- :param deferred:
- when True, the column property is "deferred", meaning that
- it does not load immediately, and is instead loaded when the
- attribute is first accessed on an instance. See also
- :func:`~sqlalchemy.orm.deferred`.
-
- :param doc:
- optional string that will be applied as the doc on the
- class-bound descriptor.
-
- :param expire_on_flush=True:
- Disable expiry on flush. A column_property() which refers
- to a SQL expression (and not a single table-bound column)
- is considered to be a "read only" property; populating it
- has no effect on the state of data, and it can only return
- database state. For this reason a column_property()'s value
- is expired whenever the parent object is involved in a
- flush, that is, has any kind of "dirty" state within a flush.
- Setting this parameter to ``False`` will have the effect of
- leaving any existing value present after the flush proceeds.
- Note however that the :class:`.Session` with default expiration
- settings still expires
- all attributes after a :meth:`.Session.commit` call, however.
-
- :param info: Optional data dictionary which will be populated into the
- :attr:`.MapperProperty.info` attribute of this object.
-
- :param raiseload: if True, indicates the column should raise an error
- when undeferred, rather than loading the value. This can be
- altered at query time by using the :func:`.deferred` option with
- raiseload=False.
-
- .. versionadded:: 1.4
-
- .. seealso::
-
- :ref:`deferred_raiseload`
-
- .. seealso::
-
- :ref:`column_property_options` - to map columns while including
- mapping options
-
- :ref:`mapper_column_property_sql_expressions` - to map SQL
- expressions
-
- """
+ def __init__(
+ self, column: sql.ColumnElement[_T], *additional_columns, **kwargs
+ ):
super(ColumnProperty, self).__init__()
+ columns = (column,) + additional_columns
self._orig_columns = [
coercions.expect(roles.LabeledColumnExprRole, c) for c in columns
]
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index e6d16f178..15259f130 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -2809,6 +2809,8 @@ class FromStatement(GroupedElement, SelectBase, Executable):
class AliasOption(interfaces.LoaderOption):
+ inherit_cache = False
+
@util.deprecated(
"1.4",
"The :class:`.AliasOption` is not necessary "
@@ -2822,8 +2824,6 @@ class AliasOption(interfaces.LoaderOption):
"""
- inherit_cache = False
-
def process_compile_state(self, compile_state):
pass
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py
index fb4723e29..330d45430 100644
--- a/lib/sqlalchemy/orm/relationships.py
+++ b/lib/sqlalchemy/orm/relationships.py
@@ -15,6 +15,11 @@ and `secondaryjoin` aspects of :func:`_orm.relationship`.
"""
import collections
import re
+from typing import Callable
+from typing import Generic
+from typing import Type
+from typing import TypeVar
+from typing import Union
import weakref
from . import attributes
@@ -48,6 +53,8 @@ from ..sql.util import join_condition
from ..sql.util import selectables_overlap
from ..sql.util import visit_binary_product
+_RC = TypeVar("_RC")
+
def remote(expr):
"""Annotate a portion of a primaryjoin expression
@@ -89,7 +96,7 @@ def foreign(expr):
@log.class_logger
-class RelationshipProperty(StrategizedProperty):
+class RelationshipProperty(StrategizedProperty, Generic[_RC]):
"""Describes an object property that holds a single item or list
of items that correspond to a related database table.
@@ -118,7 +125,7 @@ class RelationshipProperty(StrategizedProperty):
def __init__(
self,
- argument,
+ argument: Union[str, Type[_RC], Callable[[], Type[_RC]]],
secondary=None,
primaryjoin=None,
secondaryjoin=None,
@@ -154,821 +161,6 @@ class RelationshipProperty(StrategizedProperty):
sync_backref=None,
_legacy_inactive_history_style=False,
):
- """Provide a relationship between two mapped classes.
-
- This corresponds to a parent-child or associative table relationship.
- The constructed class is an instance of
- :class:`.RelationshipProperty`.
-
- A typical :func:`_orm.relationship`, used in a classical mapping::
-
- mapper(Parent, properties={
- 'children': relationship(Child)
- })
-
- Some arguments accepted by :func:`_orm.relationship`
- optionally accept a
- callable function, which when called produces the desired value.
- The callable is invoked by the parent :class:`_orm.Mapper` at "mapper
- initialization" time, which happens only when mappers are first used,
- and is assumed to be after all mappings have been constructed. This
- can be used to resolve order-of-declaration and other dependency
- issues, such as if ``Child`` is declared below ``Parent`` in the same
- file::
-
- mapper(Parent, properties={
- "children":relationship(lambda: Child,
- order_by=lambda: Child.id)
- })
-
- When using the :ref:`declarative_toplevel` extension, the Declarative
- initializer allows string arguments to be passed to
- :func:`_orm.relationship`. These string arguments are converted into
- callables that evaluate the string as Python code, using the
- Declarative class-registry as a namespace. This allows the lookup of
- related classes to be automatic via their string name, and removes the
- need for related classes to be imported into the local module space
- before the dependent classes have been declared. It is still required
- that the modules in which these related classes appear are imported
- anywhere in the application at some point before the related mappings
- are actually used, else a lookup error will be raised when the
- :func:`_orm.relationship`
- attempts to resolve the string reference to the
- related class. An example of a string- resolved class is as
- follows::
-
- from sqlalchemy.ext.declarative import declarative_base
-
- Base = declarative_base()
-
- class Parent(Base):
- __tablename__ = 'parent'
- id = Column(Integer, primary_key=True)
- children = relationship("Child", order_by="Child.id")
-
- .. seealso::
-
- :ref:`relationship_config_toplevel` - Full introductory and
- reference documentation for :func:`_orm.relationship`.
-
- :ref:`orm_tutorial_relationship` - ORM tutorial introduction.
-
- :param argument:
- A mapped class, or actual :class:`_orm.Mapper` instance,
- representing
- the target of the relationship.
-
- :paramref:`_orm.relationship.argument`
- may also be passed as a callable
- function which is evaluated at mapper initialization time, and may
- be passed as a string name when using Declarative.
-
- .. warning:: Prior to SQLAlchemy 1.3.16, this value is interpreted
- using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- .. versionchanged 1.3.16::
-
- The string evaluation of the main "argument" no longer accepts an
- open ended Python expression, instead only accepting a string
- class name or dotted package-qualified name.
-
- .. seealso::
-
- :ref:`declarative_configuring_relationships` - further detail
- on relationship configuration when using Declarative.
-
- :param secondary:
- For a many-to-many relationship, specifies the intermediary
- table, and is typically an instance of :class:`_schema.Table`.
- In less common circumstances, the argument may also be specified
- as an :class:`_expression.Alias` construct, or even a
- :class:`_expression.Join` construct.
-
- :paramref:`_orm.relationship.secondary` may
- also be passed as a callable function which is evaluated at
- mapper initialization time. When using Declarative, it may also
- be a string argument noting the name of a :class:`_schema.Table`
- that is
- present in the :class:`_schema.MetaData`
- collection associated with the
- parent-mapped :class:`_schema.Table`.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- The :paramref:`_orm.relationship.secondary` keyword argument is
- typically applied in the case where the intermediary
- :class:`_schema.Table`
- is not otherwise expressed in any direct class mapping. If the
- "secondary" table is also explicitly mapped elsewhere (e.g. as in
- :ref:`association_pattern`), one should consider applying the
- :paramref:`_orm.relationship.viewonly` flag so that this
- :func:`_orm.relationship`
- is not used for persistence operations which
- may conflict with those of the association object pattern.
-
- .. seealso::
-
- :ref:`relationships_many_to_many` - Reference example of "many
- to many".
-
- :ref:`orm_tutorial_many_to_many` - ORM tutorial introduction to
- many-to-many relationships.
-
- :ref:`self_referential_many_to_many` - Specifics on using
- many-to-many in a self-referential case.
-
- :ref:`declarative_many_to_many` - Additional options when using
- Declarative.
-
- :ref:`association_pattern` - an alternative to
- :paramref:`_orm.relationship.secondary`
- when composing association
- table relationships, allowing additional attributes to be
- specified on the association table.
-
- :ref:`composite_secondary_join` - a lesser-used pattern which
- in some cases can enable complex :func:`_orm.relationship` SQL
- conditions to be used.
-
- .. versionadded:: 0.9.2 :paramref:`_orm.relationship.secondary`
- works
- more effectively when referring to a :class:`_expression.Join`
- instance.
-
- :param active_history=False:
- When ``True``, indicates that the "previous" value for a
- many-to-one reference should be loaded when replaced, if
- not already loaded. Normally, history tracking logic for
- simple many-to-ones only needs to be aware of the "new"
- value in order to perform a flush. This flag is available
- for applications that make use of
- :func:`.attributes.get_history` which also need to know
- the "previous" value of the attribute.
-
- :param backref:
- Indicates the string name of a property to be placed on the related
- mapper's class that will handle this relationship in the other
- direction. The other property will be created automatically
- when the mappers are configured. Can also be passed as a
- :func:`.backref` object to control the configuration of the
- new relationship.
-
- .. seealso::
-
- :ref:`relationships_backref` - Introductory documentation and
- examples.
-
- :paramref:`_orm.relationship.back_populates` - alternative form
- of backref specification.
-
- :func:`.backref` - allows control over :func:`_orm.relationship`
- configuration when using :paramref:`_orm.relationship.backref`.
-
-
- :param back_populates:
- Takes a string name and has the same meaning as
- :paramref:`_orm.relationship.backref`, except the complementing
- property is **not** created automatically, and instead must be
- configured explicitly on the other mapper. The complementing
- property should also indicate
- :paramref:`_orm.relationship.back_populates` to this relationship to
- ensure proper functioning.
-
- .. seealso::
-
- :ref:`relationships_backref` - Introductory documentation and
- examples.
-
- :paramref:`_orm.relationship.backref` - alternative form
- of backref specification.
-
- :param overlaps:
- A string name or comma-delimited set of names of other relationships
- on either this mapper, a descendant mapper, or a target mapper with
- which this relationship may write to the same foreign keys upon
- persistence. The only effect this has is to eliminate the
- warning that this relationship will conflict with another upon
- persistence. This is used for such relationships that are truly
- capable of conflicting with each other on write, but the application
- will ensure that no such conflicts occur.
-
- .. versionadded:: 1.4
-
- .. seealso::
-
- :ref:`error_qzyx` - usage example
-
- :param bake_queries=True:
- Enable :ref:`lambda caching <engine_lambda_caching>` for loader
- strategies, if applicable, which adds a performance gain to the
- construction of SQL constructs used by loader strategies, in addition
- to the usual SQL statement caching used throughout SQLAlchemy. This
- parameter currently applies only to the "lazy" and "selectin" loader
- strategies. There is generally no reason to set this parameter to
- False.
-
- .. versionchanged:: 1.4 Relationship loaders no longer use the
- previous "baked query" system of query caching. The "lazy"
- and "selectin" loaders make use of the "lambda cache" system
- for the construction of SQL constructs,
- as well as the usual SQL caching system that is throughout
- SQLAlchemy as of the 1.4 series.
-
- :param cascade:
- A comma-separated list of cascade rules which determines how
- Session operations should be "cascaded" from parent to child.
- This defaults to ``False``, which means the default cascade
- should be used - this default cascade is ``"save-update, merge"``.
-
- The available cascades are ``save-update``, ``merge``,
- ``expunge``, ``delete``, ``delete-orphan``, and ``refresh-expire``.
- An additional option, ``all`` indicates shorthand for
- ``"save-update, merge, refresh-expire,
- expunge, delete"``, and is often used as in ``"all, delete-orphan"``
- to indicate that related objects should follow along with the
- parent object in all cases, and be deleted when de-associated.
-
- .. seealso::
-
- :ref:`unitofwork_cascades` - Full detail on each of the available
- cascade options.
-
- :ref:`tutorial_delete_cascade` - Tutorial example describing
- a delete cascade.
-
- :param cascade_backrefs=False:
- Legacy; this flag is always False.
-
- .. versionchanged:: 2.0 "cascade_backrefs" functionality has been
- removed.
-
- :param collection_class:
- A class or callable that returns a new list-holding object. will
- be used in place of a plain list for storing elements.
-
- .. seealso::
-
- :ref:`custom_collections` - Introductory documentation and
- examples.
-
- :param comparator_factory:
- A class which extends :class:`.RelationshipProperty.Comparator`
- which provides custom SQL clause generation for comparison
- operations.
-
- .. seealso::
-
- :class:`.PropComparator` - some detail on redefining comparators
- at this level.
-
- :ref:`custom_comparators` - Brief intro to this feature.
-
-
- :param distinct_target_key=None:
- Indicate if a "subquery" eager load should apply the DISTINCT
- keyword to the innermost SELECT statement. When left as ``None``,
- the DISTINCT keyword will be applied in those cases when the target
- columns do not comprise the full primary key of the target table.
- When set to ``True``, the DISTINCT keyword is applied to the
- innermost SELECT unconditionally.
-
- It may be desirable to set this flag to False when the DISTINCT is
- reducing performance of the innermost subquery beyond that of what
- duplicate innermost rows may be causing.
-
- .. versionchanged:: 0.9.0 -
- :paramref:`_orm.relationship.distinct_target_key` now defaults to
- ``None``, so that the feature enables itself automatically for
- those cases where the innermost query targets a non-unique
- key.
-
- .. seealso::
-
- :ref:`loading_toplevel` - includes an introduction to subquery
- eager loading.
-
- :param doc:
- Docstring which will be applied to the resulting descriptor.
-
- :param foreign_keys:
-
- A list of columns which are to be used as "foreign key"
- columns, or columns which refer to the value in a remote
- column, within the context of this :func:`_orm.relationship`
- object's :paramref:`_orm.relationship.primaryjoin` condition.
- That is, if the :paramref:`_orm.relationship.primaryjoin`
- condition of this :func:`_orm.relationship` is ``a.id ==
- b.a_id``, and the values in ``b.a_id`` are required to be
- present in ``a.id``, then the "foreign key" column of this
- :func:`_orm.relationship` is ``b.a_id``.
-
- In normal cases, the :paramref:`_orm.relationship.foreign_keys`
- parameter is **not required.** :func:`_orm.relationship` will
- automatically determine which columns in the
- :paramref:`_orm.relationship.primaryjoin` condition are to be
- considered "foreign key" columns based on those
- :class:`_schema.Column` objects that specify
- :class:`_schema.ForeignKey`,
- or are otherwise listed as referencing columns in a
- :class:`_schema.ForeignKeyConstraint` construct.
- :paramref:`_orm.relationship.foreign_keys` is only needed when:
-
- 1. There is more than one way to construct a join from the local
- table to the remote table, as there are multiple foreign key
- references present. Setting ``foreign_keys`` will limit the
- :func:`_orm.relationship`
- to consider just those columns specified
- here as "foreign".
-
- 2. The :class:`_schema.Table` being mapped does not actually have
- :class:`_schema.ForeignKey` or
- :class:`_schema.ForeignKeyConstraint`
- constructs present, often because the table
- was reflected from a database that does not support foreign key
- reflection (MySQL MyISAM).
-
- 3. The :paramref:`_orm.relationship.primaryjoin`
- argument is used to
- construct a non-standard join condition, which makes use of
- columns or expressions that do not normally refer to their
- "parent" column, such as a join condition expressed by a
- complex comparison using a SQL function.
-
- The :func:`_orm.relationship` construct will raise informative
- error messages that suggest the use of the
- :paramref:`_orm.relationship.foreign_keys` parameter when
- presented with an ambiguous condition. In typical cases,
- if :func:`_orm.relationship` doesn't raise any exceptions, the
- :paramref:`_orm.relationship.foreign_keys` parameter is usually
- not needed.
-
- :paramref:`_orm.relationship.foreign_keys` may also be passed as a
- callable function which is evaluated at mapper initialization time,
- and may be passed as a Python-evaluable string when using
- Declarative.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- .. seealso::
-
- :ref:`relationship_foreign_keys`
-
- :ref:`relationship_custom_foreign`
-
- :func:`.foreign` - allows direct annotation of the "foreign"
- columns within a :paramref:`_orm.relationship.primaryjoin`
- condition.
-
- :param info: Optional data dictionary which will be populated into the
- :attr:`.MapperProperty.info` attribute of this object.
-
- :param innerjoin=False:
- When ``True``, joined eager loads will use an inner join to join
- against related tables instead of an outer join. The purpose
- of this option is generally one of performance, as inner joins
- generally perform better than outer joins.
-
- This flag can be set to ``True`` when the relationship references an
- object via many-to-one using local foreign keys that are not
- nullable, or when the reference is one-to-one or a collection that
- is guaranteed to have one or at least one entry.
-
- The option supports the same "nested" and "unnested" options as
- that of :paramref:`_orm.joinedload.innerjoin`. See that flag
- for details on nested / unnested behaviors.
-
- .. seealso::
-
- :paramref:`_orm.joinedload.innerjoin` - the option as specified by
- loader option, including detail on nesting behavior.
-
- :ref:`what_kind_of_loading` - Discussion of some details of
- various loader options.
-
-
- :param join_depth:
- When non-``None``, an integer value indicating how many levels
- deep "eager" loaders should join on a self-referring or cyclical
- relationship. The number counts how many times the same Mapper
- shall be present in the loading condition along a particular join
- branch. When left at its default of ``None``, eager loaders
- will stop chaining when they encounter a the same target mapper
- which is already higher up in the chain. This option applies
- both to joined- and subquery- eager loaders.
-
- .. seealso::
-
- :ref:`self_referential_eager_loading` - Introductory documentation
- and examples.
-
- :param lazy='select': specifies
- How the related items should be loaded. Default value is
- ``select``. Values include:
-
- * ``select`` - items should be loaded lazily when the property is
- first accessed, using a separate SELECT statement, or identity map
- fetch for simple many-to-one references.
-
- * ``immediate`` - items should be loaded as the parents are loaded,
- using a separate SELECT statement, or identity map fetch for
- simple many-to-one references.
-
- * ``joined`` - items should be loaded "eagerly" in the same query as
- that of the parent, using a JOIN or LEFT OUTER JOIN. Whether
- the join is "outer" or not is determined by the
- :paramref:`_orm.relationship.innerjoin` parameter.
-
- * ``subquery`` - items should be loaded "eagerly" as the parents are
- loaded, using one additional SQL statement, which issues a JOIN to
- a subquery of the original statement, for each collection
- requested.
-
- * ``selectin`` - items should be loaded "eagerly" as the parents
- are loaded, using one or more additional SQL statements, which
- issues a JOIN to the immediate parent object, specifying primary
- key identifiers using an IN clause.
-
- .. versionadded:: 1.2
-
- * ``noload`` - no loading should occur at any time. This is to
- support "write-only" attributes, or attributes which are
- populated in some manner specific to the application.
-
- * ``raise`` - lazy loading is disallowed; accessing
- the attribute, if its value were not already loaded via eager
- loading, will raise an :exc:`~sqlalchemy.exc.InvalidRequestError`.
- This strategy can be used when objects are to be detached from
- their attached :class:`.Session` after they are loaded.
-
- .. versionadded:: 1.1
-
- * ``raise_on_sql`` - lazy loading that emits SQL is disallowed;
- accessing the attribute, if its value were not already loaded via
- eager loading, will raise an
- :exc:`~sqlalchemy.exc.InvalidRequestError`, **if the lazy load
- needs to emit SQL**. If the lazy load can pull the related value
- from the identity map or determine that it should be None, the
- value is loaded. This strategy can be used when objects will
- remain associated with the attached :class:`.Session`, however
- additional SELECT statements should be blocked.
-
- .. versionadded:: 1.1
-
- * ``dynamic`` - the attribute will return a pre-configured
- :class:`_query.Query` object for all read
- operations, onto which further filtering operations can be
- applied before iterating the results. See
- the section :ref:`dynamic_relationship` for more details.
-
- * True - a synonym for 'select'
-
- * False - a synonym for 'joined'
-
- * None - a synonym for 'noload'
-
- .. seealso::
-
- :doc:`/orm/loading_relationships` - Full documentation on
- relationship loader configuration.
-
- :ref:`dynamic_relationship` - detail on the ``dynamic`` option.
-
- :ref:`collections_noload_raiseload` - notes on "noload" and "raise"
-
- :param load_on_pending=False:
- Indicates loading behavior for transient or pending parent objects.
-
- When set to ``True``, causes the lazy-loader to
- issue a query for a parent object that is not persistent, meaning it
- has never been flushed. This may take effect for a pending object
- when autoflush is disabled, or for a transient object that has been
- "attached" to a :class:`.Session` but is not part of its pending
- collection.
-
- The :paramref:`_orm.relationship.load_on_pending`
- flag does not improve
- behavior when the ORM is used normally - object references should be
- constructed at the object level, not at the foreign key level, so
- that they are present in an ordinary way before a flush proceeds.
- This flag is not not intended for general use.
-
- .. seealso::
-
- :meth:`.Session.enable_relationship_loading` - this method
- establishes "load on pending" behavior for the whole object, and
- also allows loading on objects that remain transient or
- detached.
-
- :param order_by:
- Indicates the ordering that should be applied when loading these
- items. :paramref:`_orm.relationship.order_by`
- is expected to refer to
- one of the :class:`_schema.Column`
- objects to which the target class is
- mapped, or the attribute itself bound to the target class which
- refers to the column.
-
- :paramref:`_orm.relationship.order_by`
- may also be passed as a callable
- function which is evaluated at mapper initialization time, and may
- be passed as a Python-evaluable string when using Declarative.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- :param passive_deletes=False:
- Indicates loading behavior during delete operations.
-
- A value of True indicates that unloaded child items should not
- be loaded during a delete operation on the parent. Normally,
- when a parent item is deleted, all child items are loaded so
- that they can either be marked as deleted, or have their
- foreign key to the parent set to NULL. Marking this flag as
- True usually implies an ON DELETE <CASCADE|SET NULL> rule is in
- place which will handle updating/deleting child rows on the
- database side.
-
- Additionally, setting the flag to the string value 'all' will
- disable the "nulling out" of the child foreign keys, when the parent
- object is deleted and there is no delete or delete-orphan cascade
- enabled. This is typically used when a triggering or error raise
- scenario is in place on the database side. Note that the foreign
- key attributes on in-session child objects will not be changed after
- a flush occurs so this is a very special use-case setting.
- Additionally, the "nulling out" will still occur if the child
- object is de-associated with the parent.
-
- .. seealso::
-
- :ref:`passive_deletes` - Introductory documentation
- and examples.
-
- :param passive_updates=True:
- Indicates the persistence behavior to take when a referenced
- primary key value changes in place, indicating that the referencing
- foreign key columns will also need their value changed.
-
- When True, it is assumed that ``ON UPDATE CASCADE`` is configured on
- the foreign key in the database, and that the database will
- handle propagation of an UPDATE from a source column to
- dependent rows. When False, the SQLAlchemy
- :func:`_orm.relationship`
- construct will attempt to emit its own UPDATE statements to
- modify related targets. However note that SQLAlchemy **cannot**
- emit an UPDATE for more than one level of cascade. Also,
- setting this flag to False is not compatible in the case where
- the database is in fact enforcing referential integrity, unless
- those constraints are explicitly "deferred", if the target backend
- supports it.
-
- It is highly advised that an application which is employing
- mutable primary keys keeps ``passive_updates`` set to True,
- and instead uses the referential integrity features of the database
- itself in order to handle the change efficiently and fully.
-
- .. seealso::
-
- :ref:`passive_updates` - Introductory documentation and
- examples.
-
- :paramref:`.mapper.passive_updates` - a similar flag which
- takes effect for joined-table inheritance mappings.
-
- :param post_update:
- This indicates that the relationship should be handled by a
- second UPDATE statement after an INSERT or before a
- DELETE. Currently, it also will issue an UPDATE after the
- instance was UPDATEd as well, although this technically should
- be improved. This flag is used to handle saving bi-directional
- dependencies between two individual rows (i.e. each row
- references the other), where it would otherwise be impossible to
- INSERT or DELETE both rows fully since one row exists before the
- other. Use this flag when a particular mapping arrangement will
- incur two rows that are dependent on each other, such as a table
- that has a one-to-many relationship to a set of child rows, and
- also has a column that references a single child row within that
- list (i.e. both tables contain a foreign key to each other). If
- a flush operation returns an error that a "cyclical
- dependency" was detected, this is a cue that you might want to
- use :paramref:`_orm.relationship.post_update` to "break" the cycle.
-
- .. seealso::
-
- :ref:`post_update` - Introductory documentation and examples.
-
- :param primaryjoin:
- A SQL expression that will be used as the primary
- join of the child object against the parent object, or in a
- many-to-many relationship the join of the parent object to the
- association table. By default, this value is computed based on the
- foreign key relationships of the parent and child tables (or
- association table).
-
- :paramref:`_orm.relationship.primaryjoin` may also be passed as a
- callable function which is evaluated at mapper initialization time,
- and may be passed as a Python-evaluable string when using
- Declarative.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- .. seealso::
-
- :ref:`relationship_primaryjoin`
-
- :param remote_side:
- Used for self-referential relationships, indicates the column or
- list of columns that form the "remote side" of the relationship.
-
- :paramref:`_orm.relationship.remote_side` may also be passed as a
- callable function which is evaluated at mapper initialization time,
- and may be passed as a Python-evaluable string when using
- Declarative.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- .. seealso::
-
- :ref:`self_referential` - in-depth explanation of how
- :paramref:`_orm.relationship.remote_side`
- is used to configure self-referential relationships.
-
- :func:`.remote` - an annotation function that accomplishes the
- same purpose as :paramref:`_orm.relationship.remote_side`,
- typically
- when a custom :paramref:`_orm.relationship.primaryjoin` condition
- is used.
-
- :param query_class:
- A :class:`_query.Query`
- subclass that will be used internally by the
- ``AppenderQuery`` returned by a "dynamic" relationship, that
- is, a relationship that specifies ``lazy="dynamic"`` or was
- otherwise constructed using the :func:`_orm.dynamic_loader`
- function.
-
- .. seealso::
-
- :ref:`dynamic_relationship` - Introduction to "dynamic"
- relationship loaders.
-
- :param secondaryjoin:
- A SQL expression that will be used as the join of
- an association table to the child object. By default, this value is
- computed based on the foreign key relationships of the association
- and child tables.
-
- :paramref:`_orm.relationship.secondaryjoin` may also be passed as a
- callable function which is evaluated at mapper initialization time,
- and may be passed as a Python-evaluable string when using
- Declarative.
-
- .. warning:: When passed as a Python-evaluable string, the
- argument is interpreted using Python's ``eval()`` function.
- **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
- See :ref:`declarative_relationship_eval` for details on
- declarative evaluation of :func:`_orm.relationship` arguments.
-
- .. seealso::
-
- :ref:`relationship_primaryjoin`
-
- :param single_parent:
- When True, installs a validator which will prevent objects
- from being associated with more than one parent at a time.
- This is used for many-to-one or many-to-many relationships that
- should be treated either as one-to-one or one-to-many. Its usage
- is optional, except for :func:`_orm.relationship` constructs which
- are many-to-one or many-to-many and also
- specify the ``delete-orphan`` cascade option. The
- :func:`_orm.relationship` construct itself will raise an error
- instructing when this option is required.
-
- .. seealso::
-
- :ref:`unitofwork_cascades` - includes detail on when the
- :paramref:`_orm.relationship.single_parent`
- flag may be appropriate.
-
- :param uselist:
- A boolean that indicates if this property should be loaded as a
- list or a scalar. In most cases, this value is determined
- automatically by :func:`_orm.relationship` at mapper configuration
- time, based on the type and direction
- of the relationship - one to many forms a list, many to one
- forms a scalar, many to many is a list. If a scalar is desired
- where normally a list would be present, such as a bi-directional
- one-to-one relationship, set :paramref:`_orm.relationship.uselist`
- to
- False.
-
- The :paramref:`_orm.relationship.uselist`
- flag is also available on an
- existing :func:`_orm.relationship`
- construct as a read-only attribute,
- which can be used to determine if this :func:`_orm.relationship`
- deals
- with collections or scalar attributes::
-
- >>> User.addresses.property.uselist
- True
-
- .. seealso::
-
- :ref:`relationships_one_to_one` - Introduction to the "one to
- one" relationship pattern, which is typically when the
- :paramref:`_orm.relationship.uselist` flag is needed.
-
- :param viewonly=False:
- When set to ``True``, the relationship is used only for loading
- objects, and not for any persistence operation. A
- :func:`_orm.relationship` which specifies
- :paramref:`_orm.relationship.viewonly` can work
- with a wider range of SQL operations within the
- :paramref:`_orm.relationship.primaryjoin` condition, including
- operations that feature the use of a variety of comparison operators
- as well as SQL functions such as :func:`_expression.cast`. The
- :paramref:`_orm.relationship.viewonly`
- flag is also of general use when defining any kind of
- :func:`_orm.relationship` that doesn't represent
- the full set of related objects, to prevent modifications of the
- collection from resulting in persistence operations.
-
- When using the :paramref:`_orm.relationship.viewonly` flag in
- conjunction with backrefs, the originating relationship for a
- particular state change will not produce state changes within the
- viewonly relationship. This is the behavior implied by
- :paramref:`_orm.relationship.sync_backref` being set to False.
-
- .. versionchanged:: 1.3.17 - the
- :paramref:`_orm.relationship.sync_backref` flag is set to False
- when using viewonly in conjunction with backrefs.
-
- .. seealso::
-
- :paramref:`_orm.relationship.sync_backref`
-
- :param sync_backref:
- A boolean that enables the events used to synchronize the in-Python
- attributes when this relationship is target of either
- :paramref:`_orm.relationship.backref` or
- :paramref:`_orm.relationship.back_populates`.
-
- Defaults to ``None``, which indicates that an automatic value should
- be selected based on the value of the
- :paramref:`_orm.relationship.viewonly` flag. When left at its
- default, changes in state will be back-populated only if neither
- sides of a relationship is viewonly.
-
- .. versionadded:: 1.3.17
-
- .. versionchanged:: 1.4 - A relationship that specifies
- :paramref:`_orm.relationship.viewonly` automatically implies
- that :paramref:`_orm.relationship.sync_backref` is ``False``.
-
- .. seealso::
-
- :paramref:`_orm.relationship.viewonly`
-
- :param omit_join:
- Allows manual control over the "selectin" automatic join
- optimization. Set to ``False`` to disable the "omit join" feature
- added in SQLAlchemy 1.3; or leave as ``None`` to leave automatic
- optimization in place.
-
- .. note:: This flag may only be set to ``False``. It is not
- necessary to set it to ``True`` as the "omit_join" optimization is
- automatically detected; if it is not detected, then the
- optimization is not supported.
-
- .. versionchanged:: 1.3.11 setting ``omit_join`` to True will now
- emit a warning as this was not the intended use of this flag.
-
- .. versionadded:: 1.3
-
-
- """
super(RelationshipProperty, self).__init__()
self.uselist = uselist
diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py
index ead0d06ef..47da85716 100644
--- a/lib/sqlalchemy/orm/scoping.py
+++ b/lib/sqlalchemy/orm/scoping.py
@@ -5,8 +5,8 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: https://www.opensource.org/licenses/mit-license.php
-from . import class_mapper
from . import exc as orm_exc
+from .base import class_mapper
from .session import Session
from .. import exc as sa_exc
from ..util import create_proxy_methods
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index e0dd5941d..c1ce3b845 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -968,172 +968,6 @@ class LoaderCriteriaOption(CriteriaOption):
propagate_to_loaders=True,
track_closure_variables=True,
):
- """Add additional WHERE criteria to the load for all occurrences of
- a particular entity.
-
- .. versionadded:: 1.4
-
- The :func:`_orm.with_loader_criteria` option is intended to add
- limiting criteria to a particular kind of entity in a query,
- **globally**, meaning it will apply to the entity as it appears
- in the SELECT query as well as within any subqueries, join
- conditions, and relationship loads, including both eager and lazy
- loaders, without the need for it to be specified in any particular
- part of the query. The rendering logic uses the same system used by
- single table inheritance to ensure a certain discriminator is applied
- to a table.
-
- E.g., using :term:`2.0-style` queries, we can limit the way the
- ``User.addresses`` collection is loaded, regardless of the kind
- of loading used::
-
- from sqlalchemy.orm import with_loader_criteria
-
- stmt = select(User).options(
- selectinload(User.addresses),
- with_loader_criteria(Address, Address.email_address != 'foo'))
- )
-
- Above, the "selectinload" for ``User.addresses`` will apply the
- given filtering criteria to the WHERE clause.
-
- Another example, where the filtering will be applied to the
- ON clause of the join, in this example using :term:`1.x style`
- queries::
-
- q = session.query(User).outerjoin(User.addresses).options(
- with_loader_criteria(Address, Address.email_address != 'foo'))
- )
-
- The primary purpose of :func:`_orm.with_loader_criteria` is to use
- it in the :meth:`_orm.SessionEvents.do_orm_execute` event handler
- to ensure that all occurrences of a particular entity are filtered
- in a certain way, such as filtering for access control roles. It
- also can be used to apply criteria to relationship loads. In the
- example below, we can apply a certain set of rules to all queries
- emitted by a particular :class:`_orm.Session`::
-
- session = Session(bind=engine)
-
- @event.listens_for("do_orm_execute", session)
- def _add_filtering_criteria(execute_state):
-
- 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.
-
- .. tip::
-
- When using :func:`_orm.with_loader_criteria` option in
- conjunction with the :func:`_orm.contains_eager` loader option,
- it's important to note that :func:`_orm.with_loader_criteria` only
- affects the part of the query that determines what SQL is rendered
- in terms of the WHERE and FROM clauses. The
- :func:`_orm.contains_eager` option does not affect the rendering of
- the SELECT statement outside of the columns clause, so does not have
- any interaction with the :func:`_orm.with_loader_criteria` option.
- However, the way things "work" is that :func:`_orm.contains_eager`
- is meant to be used with a query that is already selecting from the
- additional entities in some way, where
- :func:`_orm.with_loader_criteria` can apply it's additional
- criteria.
-
- In the example below, assuming a mapping relationship as
- ``A -> A.bs -> B``, the given :func:`_orm.with_loader_criteria`
- option will affect the way in which the JOIN is rendered::
-
- stmt = select(A).join(A.bs).options(
- contains_eager(A.bs),
- with_loader_criteria(B, B.flag == 1)
- )
-
- Above, the given :func:`_orm.with_loader_criteria` option will
- affect the ON clause of the JOIN that is specified by
- ``.join(A.bs)``, so is applied as expected. The
- :func:`_orm.contains_eager` option has the effect that columns from
- ``B`` are added to the columns clause::
-
- SELECT
- b.id, b.a_id, b.data, b.flag,
- a.id AS id_1,
- a.data AS data_1
- FROM a JOIN b ON a.id = b.a_id AND b.flag = :flag_1
-
-
- The use of the :func:`_orm.contains_eager` option within the above
- statement has no effect on the behavior of the
- :func:`_orm.with_loader_criteria` option. If the
- :func:`_orm.contains_eager` option were omitted, the SQL would be
- the same as regards the FROM and WHERE clauses, where
- :func:`_orm.with_loader_criteria` continues to add its criteria to
- the ON clause of the JOIN. The addition of
- :func:`_orm.contains_eager` only affects the columns clause, in that
- additional columns against ``b`` are added which are then consumed
- by the ORM to produce ``B`` instances.
-
- .. 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
- will apply.
-
- :param where_criteria: a Core SQL expression that applies limiting
- criteria. This may also be a "lambda:" or Python function that
- accepts a target class as an argument, when the given class is
- a base with many different mapped subclasses.
-
- :param include_aliases: if True, apply the rule to :func:`_orm.aliased`
- constructs as well.
-
- :param propagate_to_loaders: defaults to True, apply to relationship
- loaders such as lazy loaders.
-
-
- .. seealso::
-
- :ref:`examples_session_orm_events` - includes examples of using
- :func:`_orm.with_loader_criteria`.
-
- :ref:`do_orm_execute_global_criteria` - basic example on how to
- combine :func:`_orm.with_loader_criteria` with the
- :meth:`_orm.SessionEvents.do_orm_execute` event.
-
- :param track_closure_variables: when False, closure variables inside
- of a lambda expression will not be used as part of
- any cache key. This allows more complex expressions to be used
- inside of a lambda expression but requires that the lambda ensures
- it returns the identical SQL every time given a particular class.
-
- .. versionadded:: 1.4.0b2
-
- """
-
entity = inspection.inspect(entity_or_base, False)
if entity is None:
self.root_entity = entity_or_base