diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-12-29 20:54:29 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-25 09:28:28 -0500 |
commit | 93855ed623ceedffc02dee06c9a46c37dd26286b (patch) | |
tree | 5fdb783ea642d99693fd284dcbc04d4691423d16 /lib/sqlalchemy/orm/util.py | |
parent | 78e598e3a5b8df7419a600c291f90260e598c9b7 (diff) | |
download | sqlalchemy-93855ed623ceedffc02dee06c9a46c37dd26286b.tar.gz |
Implement relationship to AliasedClass; deprecate non primary mappers
Implemented a new feature whereby the :class:`.AliasedClass` construct can
now be used as the target of a :func:`.relationship`. This allows the
concept of "non primary mappers" to no longer be necessary, as the
:class:`.AliasedClass` is much easier to configure and automatically inherits
all the relationships of the mapped class, as well as preserves the
ability for loader options to work normally.
- introduce new name for mapped_table, "persist_selectable". this is
the selectable that selects against the local mapper and its superclasses,
but does not include columns local only to subclasses.
- relationship gains "entity" which is the mapper or aliasedinsp.
- clarfiy name "entity" vs. "query_entity" in loader strategies.
Fixes: #4423
Fixes: #4422
Fixes: #4421
Fixes: #3348
Change-Id: Ic3609b43dc4ed115006da9ad9189e574dc0c72d9
Diffstat (limited to 'lib/sqlalchemy/orm/util.py')
-rw-r--r-- | lib/sqlalchemy/orm/util.py | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 776278469..8873a6a72 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -394,21 +394,30 @@ class ORMAdapter(sql_util.ColumnAdapter): class AliasedClass(object): r"""Represents an "aliased" form of a mapped class for usage with Query. - The ORM equivalent of a :func:`sqlalchemy.sql.expression.alias` + The ORM equivalent of a :func:`~sqlalchemy.sql.expression.alias` construct, this object mimics the mapped class using a - __getattr__ scheme and maintains a reference to a + ``__getattr__`` scheme and maintains a reference to a real :class:`~sqlalchemy.sql.expression.Alias` object. - Usage is via the :func:`.orm.aliased` function, or alternatively - via the :func:`.orm.with_polymorphic` function. - - Usage example:: + A primary purpose of :class:`.AliasedClass` is to serve as an alternate + within a SQL statement generated by the ORM, such that an existing + mapped entity can be used in multiple contexts. A simple example:: # find all pairs of users with the same name user_alias = aliased(User) session.query(User, user_alias).\ join((user_alias, User.id > user_alias.id)).\ - filter(User.name==user_alias.name) + filter(User.name == user_alias.name) + + :class:`.AliasedClass` is also capable of mapping an existing mapped + class to an entirely new selectable, provided this selectable is column- + compatible with the existing mapped selectable, and it can also be + configured in a mapping as the target of a :func:`.relationship`. + See the links below for examples. + + The :class:`.AliasedClass` object is constructed typically using the + :func:`.orm.aliased` function. It also is produced with additional + configuration when using the :func:`.orm.with_polymorphic` function. The resulting object is an instance of :class:`.AliasedClass`. This object implements an attribute scheme which produces the @@ -427,8 +436,17 @@ class AliasedClass(object): The resulting inspection object is an instance of :class:`.AliasedInsp`. - See :func:`.aliased` and :func:`.with_polymorphic` for construction - argument descriptions. + + .. seealso:: + + :func:`.aliased` + + :func:`.with_polymorphic` + + :ref:`relationship_aliased_class` + + :ref:`relationship_to_window_function` + """ @@ -564,7 +582,9 @@ class AliasedInsp(InspectionAttr): ): self.entity = entity self.mapper = mapper - self.selectable = selectable + self.selectable = ( + self.persist_selectable + ) = self.local_table = selectable self.name = name self.with_polymorphic_mappers = with_polymorphic_mappers self.polymorphic_on = polymorphic_on @@ -660,6 +680,17 @@ class AliasedInsp(InspectionAttr): assert False, "mapper %s doesn't correspond to %s" % (mapper, self) @util.memoized_property + def _get_clause(self): + onclause, replacemap = self.mapper._get_clause + return ( + self._adapter.traverse(onclause), + { + self._adapter.traverse(col): param + for col, param in replacemap.items() + }, + ) + + @util.memoized_property def _memoized_values(self): return {} @@ -970,7 +1001,7 @@ class _ORMJoin(expression.Join): dest_selectable=adapt_to, source_polymorphic=True, dest_polymorphic=True, - of_type=right_info.mapper, + of_type_mapper=right_info.mapper, ) if sj is not None: |