if col in row:
return self.parent_property._get_strategy(ColumnLoader).create_row_processor(selectcontext, path, mapper, row, adapter)
- elif not self.is_class_level or len(selectcontext.options):
+ elif not self.is_class_level:
def new_execute(state, row, **flags):
- state.set_callable(self.key, self.setup_loader(state))
+ state.set_callable(self.key, LoadDeferredColumns(state, self.key))
else:
def new_execute(state, row, **flags):
+ # reset state on the key so that deferred callables
+ # fire off on next access.
state.reset(self.key)
if self._should_log_debug:
compare_function=self.columns[0].type.compare_values,
copy_function=self.columns[0].type.copy_value,
mutable_scalars=self.columns[0].type.is_mutable(),
- callable_=self.class_level_loader,
+ callable_=self._class_level_loader,
dont_expire_missing=True
)
self.parent_property._get_strategy(ColumnLoader).setup_query(context, entity, path, adapter, **kwargs)
- def class_level_loader(self, state, props=None):
+ def _class_level_loader(self, state):
if not mapperutil._state_has_identity(state):
return None
- localparent = mapper._state_mapper(state)
-
- # adjust for the ColumnProperty associated with the instance
- # not being our own ColumnProperty.
- # TODO: this may no longer be relevant without entity_name.
- prop = localparent.get_property(self.key)
- if prop is not self.parent_property:
- return prop._get_strategy(DeferredColumnLoader).setup_loader(state)
-
- return LoadDeferredColumns(state, self.key, props)
+ return LoadDeferredColumns(state, self.key)
- def setup_loader(self, state, props=None, create_statement=None):
- return LoadDeferredColumns(state, self.key, props)
log.class_logger(DeferredColumnLoader)
class LoadDeferredColumns(object):
"""serializable loader object used by DeferredColumnLoader"""
- def __init__(self, *args):
- self.state, self.key, self.keys = args
+ def __init__(self, state, key):
+ self.state, self.key = state, key
def __call__(self):
state = self.state
- if not mapper._state_has_identity(state):
- return None
localparent = mapper._state_mapper(state)
prop = localparent.get_property(self.key)
strategy = prop._get_strategy(DeferredColumnLoader)
- if self.keys:
- toload = self.keys
- elif strategy.group:
+ if strategy.group:
toload = [
p.key for p in
localparent.iterate_properties
group = [k for k in toload if k in state.unmodified]
if strategy._should_log_debug:
- strategy.logger.debug("deferred load %s group %s" % (mapperutil.state_attribute_str(state, self.key), group and ','.join(group) or 'None'))
+ strategy.logger.debug(
+ "deferred load %s group %s" %
+ (mapperutil.state_attribute_str(state, self.key), group and ','.join(group) or 'None')
+ )
session = sessionlib._state_session(state)
if session is None:
- raise sa_exc.UnboundExecutionError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (mapperutil.state_str(state), self.key))
+ raise sa_exc.UnboundExecutionError(
+ "Parent instance %s is not bound to a Session; "
+ "deferred load operation of attribute '%s' cannot proceed" %
+ (mapperutil.state_str(state), self.key)
+ )
query = session.query(localparent)
ident = state.key[1]
_register_attribute(self,
mapper,
useobject=True,
- callable_=self.class_level_loader,
+ callable_=self._class_level_loader,
uselist = self.parent_property.uselist,
typecallable = self.parent_property.collection_class,
)
criterion = adapt_source(criterion)
return criterion
- def class_level_loader(self, state, options=None, path=None):
+ def _class_level_loader(self, state):
if not mapperutil._state_has_identity(state):
return None
- localparent = mapper._state_mapper(state)
-
- # adjust for the PropertyLoader associated with the instance
- # not being our own PropertyLoader.
- # TODO: this may no longer be relevant without entity_name
- prop = localparent.get_property(self.key)
- if prop is not self.parent_property:
- return prop._get_strategy(LazyLoader).setup_loader(state)
-
- return LoadLazyAttribute(state, self.key, options, path)
-
- def setup_loader(self, state, options=None, path=None):
- return LoadLazyAttribute(state, self.key, options, path)
+ return LoadLazyAttribute(state, self.key)
def create_row_processor(self, selectcontext, path, mapper, row, adapter):
- if not self.is_class_level or len(selectcontext.options):
- path = path + (self.key,)
+ if not self.is_class_level:
def new_execute(state, row, **flags):
# we are not the primary manager for this attribute on this class - set up a per-instance lazyloader,
- # which will override the class-level behavior
- self._init_instance_attribute(state, callable_=self.setup_loader(state, selectcontext.options, selectcontext.query._current_path + path))
+ # which will override the class-level behavior.
+ # this currently only happens when using a "lazyload" option on a "no load" attribute -
+ # "eager" attributes always have a class-level lazyloader installed.
+ self._init_instance_attribute(state, callable_=LoadLazyAttribute(state, self.key))
if self._should_log_debug:
new_execute = self.debug_callable(new_execute, self.logger, None,
def new_execute(state, row, **flags):
# we are the primary manager for this attribute on this class - reset its per-instance attribute state,
# so that the class-level lazy loader is executed when next referenced on this instance.
- # this usually is not needed unless the constructor of the object referenced the attribute before we got
- # to load data into it.
+ # this is needed in populate_existing() types of scenarios to reset any existing state.
state.reset(self.key)
if self._should_log_debug:
)
return (new_execute, None)
-
+
def _create_lazy_clause(cls, prop, reverse_direction=False):
binds = util.column_dict()
lookup = util.column_dict()
class LoadLazyAttribute(object):
"""serializable loader object used by LazyLoader"""
- def __init__(self, *args):
- self.state, self.key, self.options, self.path = args
+ def __init__(self, state, key):
+ self.state, self.key = state, key
def __getstate__(self):
- return (self.state, self.key, self.options, serialize_path(self.path))
+ return (self.state, self.key)
def __setstate__(self, state):
- self.state, self.key, self.options, path = state
- self.path = deserialize_path(path)
+ self.state, self.key = state
def __call__(self):
state = self.state
- if not mapper._state_has_identity(state):
- return None
instance_mapper = mapper._state_mapper(state)
prop = instance_mapper.get_property(self.key)
q = session.query(prop.mapper)._adapt_all_clauses()
- if self.path:
- q = q._with_current_path(self.path)
+ if state.load_path:
+ q = q._with_current_path(state.load_path + (self.key,))
# if we have a simple primary key load, use mapper.get()
# to possibly save a DB round trip
ident.append(val)
if allnulls:
return None
- if self.options:
- q = q._conditional_options(*self.options)
+ if state.load_options:
+ q = q._conditional_options(*state.load_options)
return q.get(ident)
if prop.order_by:
q = q.order_by(*util.to_list(prop.order_by))
- if self.options:
- q = q._conditional_options(*self.options)
+ if state.load_options:
+ q = q._conditional_options(*state.load_options)
q = q.filter(strategy.lazy_clause(state))
result = q.all()