diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-22 20:16:47 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-22 20:16:47 -0500 |
| commit | 743ceb045e8be8b606198f4d5c02a72abebb2fbb (patch) | |
| tree | ca3b2c4a1a36cf88eb74d32b999c37d4bc1bee1b /lib/sqlalchemy | |
| parent | 1732414076677e8fb84134325635729691f3d26d (diff) | |
| download | sqlalchemy-743ceb045e8be8b606198f4d5c02a72abebb2fbb.tar.gz | |
- Support is improved for supplying a :func:`.join` construct as the
target of :paramref:`.relationship.secondary` for the purposes
of creating very complex :func:`.relationship` join conditions.
The change includes adjustments to query joining, joined eager loading
to not render a SELECT subquery, changes to lazy loading such that
the "secondary" target is properly included in the SELECT, and
changes to declarative to better support specification of a
join() object with classes as targets.
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/ext/declarative/clsregistry.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 8 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/relationships.py | 29 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 4 |
4 files changed, 39 insertions, 6 deletions
diff --git a/lib/sqlalchemy/ext/declarative/clsregistry.py b/lib/sqlalchemy/ext/declarative/clsregistry.py index fda1cffb5..8b846746f 100644 --- a/lib/sqlalchemy/ext/declarative/clsregistry.py +++ b/lib/sqlalchemy/ext/declarative/clsregistry.py @@ -14,6 +14,7 @@ from ...orm.properties import ColumnProperty, RelationshipProperty, \ from ...schema import _get_table_key from ...orm import class_mapper, interfaces from ... import util +from ... import inspection from ... import exc import weakref @@ -207,6 +208,9 @@ class _GetColumns(object): " directly to a Column)." % key) return getattr(self.cls, key) +inspection._inspects(_GetColumns)( + lambda target: inspection.inspect(target.cls)) + class _GetTable(object): def __init__(self, key, metadata): diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index a853efc3f..26f105bec 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -292,8 +292,12 @@ class Mapper(_InspectionAttr): mapping of the class to an alternate selectable, for loading only. - The ``non_primary`` feature is rarely needed with modern - usage. + :paramref:`.Mapper.non_primary` is not an often used option, but + is useful in some specific :func:`.relationship` cases. + + .. seealso:: + + :ref:`relationship_non_primary_mapper` :param order_by: A single :class:`.Column` or list of :class:`.Column` objects for which selection operations should use as the default diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index 6fdedd382..62d4d6b6c 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -111,11 +111,14 @@ class RelationshipProperty(StrategizedProperty): strategy_class=None, _local_remote_pairs=None, query_class=None, info=None): - """Provide a relationship of a primary Mapper to a secondary Mapper. + """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`. + For an overview of basic patterns with :func:`.relationship` as + used with Declarative, see :ref:`relationship_patterns`. + A typical :func:`.relationship`, used in a classical mapping:: mapper(Parent, properties={ @@ -165,8 +168,11 @@ class RelationshipProperty(StrategizedProperty): :param secondary: for a many-to-many relationship, specifies the intermediary - table, and is an instance of :class:`.Table`. The ``secondary`` keyword - argument should generally only + table, and is typically an instance of :class:`.Table`. + In less common circumstances, the argument may also be specified + as an :class:`.Alias` construct, or even a :class:`.Join` construct. + + The ``secondary`` keyword argument should generally only be used for a table that is not otherwise expressed in any class mapping, unless this relationship is declared as view only, otherwise conflicting persistence operations can occur. @@ -175,6 +181,13 @@ class RelationshipProperty(StrategizedProperty): also be passed as a callable function which is evaluated at mapper initialization time. + .. seealso:: + + :ref:`relationships_many_to_many` + + .. versionadded:: 0.9.2 :paramref:`.relationship.secondary` works + more effectively when referring to a :class:`.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 @@ -562,6 +575,10 @@ class RelationshipProperty(StrategizedProperty): which is evaluated at mapper initialization time, and may be passed as a Python-evaluable string when using Declarative. + .. 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. @@ -593,6 +610,10 @@ class RelationshipProperty(StrategizedProperty): which is evaluated at mapper initialization time, and may be passed as a Python-evaluable string when using Declarative. + .. seealso:: + + :ref:`relationship_primaryjoin` + :param single_parent=(True|False): when True, installs a validator which will prevent objects from being associated with more than one parent at a time. @@ -2422,7 +2443,7 @@ class JoinCondition(object): if aliased: if secondary is not None: - secondary = secondary.alias() + secondary = secondary.alias(flat=True) primary_aliasizer = ClauseAdapter(secondary) secondary_aliasizer = \ ClauseAdapter(dest_selectable, diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 033e3d064..bd9b02d24 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -527,6 +527,10 @@ class LazyLoader(AbstractRelationshipLoader): def _emit_lazyload(self, strategy_options, session, state, ident_key, passive): q = session.query(self.mapper)._adapt_all_clauses() + + if self.parent_property.secondary is not None: + q = q.select_from(self.mapper, self.parent_property.secondary) + q = q._with_invoke_all_eagers(False) pending = not state.key |
