summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-01-13 17:04:35 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-01-13 17:04:35 -0500
commitb63aae2c232f980a47aa2a635c35dfa45390f451 (patch)
tree61d23fbb2884155a30e3117198668e7c59117002 /lib/sqlalchemy
parent268bb4d5f6a8c8a23d6f53014980bba58698b4b4 (diff)
downloadsqlalchemy-b63aae2c232f980a47aa2a635c35dfa45390f451.tar.gz
- The "wildcard" loader options, in particular the one set up by
the :func:`.orm.load_only` option to cover all attributes not explicitly mentioned, now takes into account the superclasses of a given entity, if that entity is mapped with inheritance mapping, so that attribute names within the superclasses are also omitted from the load. Additionally, the polymorphic discriminator column is unconditionally included in the list, just in the same way that primary key columns are, so that even with load_only() set up, polymorphic loading of subtypes continues to function correctly. fixes #3287
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/mapper.py7
-rw-r--r--lib/sqlalchemy/orm/path_registry.py14
-rw-r--r--lib/sqlalchemy/orm/strategies.py3
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py15
4 files changed, 35 insertions, 4 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 0469c2139..74d8f3860 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -2388,6 +2388,13 @@ class Mapper(InspectionAttr):
return collection
@_memoized_configured_property
+ def _should_undefer_in_wildcard(self):
+ cols = set(self.primary_key)
+ if self.polymorphic_on is not None:
+ cols.add(self.polymorphic_on)
+ return cols
+
+ @_memoized_configured_property
def _primary_key_propkeys(self):
return set([prop.key for prop in self._all_pk_props])
diff --git a/lib/sqlalchemy/orm/path_registry.py b/lib/sqlalchemy/orm/path_registry.py
index d4dbf29a0..ec80c70cc 100644
--- a/lib/sqlalchemy/orm/path_registry.py
+++ b/lib/sqlalchemy/orm/path_registry.py
@@ -52,6 +52,9 @@ class PathRegistry(object):
"""
+ is_token = False
+ is_root = False
+
def __eq__(self, other):
return other is not None and \
self.path == other.path
@@ -153,6 +156,8 @@ class RootRegistry(PathRegistry):
"""
path = ()
has_entity = False
+ is_aliased_class = False
+ is_root = True
def __getitem__(self, entity):
return entity._path_registry
@@ -168,6 +173,15 @@ class TokenRegistry(PathRegistry):
has_entity = False
+ is_token = True
+
+ def generate_for_superclasses(self):
+ if not self.parent.is_aliased_class and not self.parent.is_root:
+ for ent in self.parent.mapper.iterate_to_root():
+ yield TokenRegistry(self.parent.parent[ent], self.token)
+ else:
+ yield self
+
def __getitem__(self, entity):
raise NotImplementedError()
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 81da7ba93..8a4c8e731 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -231,7 +231,8 @@ class DeferredColumnLoader(LoaderStrategy):
(
loadopt and
'undefer_pks' in loadopt.local_opts and
- set(self.columns).intersection(self.parent.primary_key)
+ set(self.columns).intersection(
+ self.parent._should_undefer_in_wildcard)
)
or
(
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index 276da2ae0..90e4e9661 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -364,6 +364,7 @@ class _UnboundLoad(Load):
return None
token = start_path[0]
+
if isinstance(token, util.string_types):
entity = self._find_entity_basestring(query, token, raiseerr)
elif isinstance(token, PropComparator):
@@ -407,10 +408,18 @@ class _UnboundLoad(Load):
# prioritize "first class" options over those
# that were "links in the chain", e.g. "x" and "y" in
# someload("x.y.z") versus someload("x") / someload("x.y")
- if self._is_chain_link:
- effective_path.setdefault(context, "loader", loader)
+
+ if effective_path.is_token:
+ for path in effective_path.generate_for_superclasses():
+ if self._is_chain_link:
+ path.setdefault(context, "loader", loader)
+ else:
+ path.set(context, "loader", loader)
else:
- effective_path.set(context, "loader", loader)
+ if self._is_chain_link:
+ effective_path.setdefault(context, "loader", loader)
+ else:
+ effective_path.set(context, "loader", loader)
def _find_entity_prop_comparator(self, query, token, mapper, raiseerr):
if _is_aliased_class(mapper):