summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/util.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2018-12-29 20:54:29 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-01-25 09:28:28 -0500
commit93855ed623ceedffc02dee06c9a46c37dd26286b (patch)
tree5fdb783ea642d99693fd284dcbc04d4691423d16 /lib/sqlalchemy/orm/util.py
parent78e598e3a5b8df7419a600c291f90260e598c9b7 (diff)
downloadsqlalchemy-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.py53
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: