def flush(self, session, objects=None): # this context will track all the objects we want to save/update/delete, # and organize a hierarchical dependency structure. it also handles # communication with the mappers and relationships to fire off SQL # and synchronize attributes between related objects. echo = logging.is_info_enabled(self.logger) flush_context = UOWTransaction(self, session) # create the set of all objects we want to operate upon if objects is not None: # specific list passed in objset = util.Set(objects) else: # or just everything objset = util.Set(self.identity_map.values()).union(self.new) # detect persistent objects that have changes dirty = self.locate_dirty() # store objects whose fate has been decided processed = util.Set() # put all saves/updates into the flush context. detect orphans and throw them into deleted. for obj in self.new.union(dirty).intersection(objset).difference( self.deleted): if obj in processed: continue if object_mapper(obj)._is_orphan(obj): for c in [obj] + list( object_mapper(obj).cascade_iterator('delete', obj)): if c in processed: continue flush_context.register_object(c, isdelete=True) processed.add(c) else: flush_context.register_object(obj) processed.add(obj) # put all remaining deletes into the flush context. for obj in self.deleted: if (objset is not None and not obj in objset) or obj in processed: continue flush_context.register_object(obj, isdelete=True) trans = session.create_transaction(autoflush=False) flush_context.transaction = trans try: flush_context.execute() except: trans.rollback() raise trans.commit() flush_context.post_exec()
def flush(self, session, objects=None): # this context will track all the objects we want to save/update/delete, # and organize a hierarchical dependency structure. it also handles # communication with the mappers and relationships to fire off SQL # and synchronize attributes between related objects. echo = logging.is_info_enabled(self.logger) flush_context = UOWTransaction(self, session) # create the set of all objects we want to operate upon if objects is not None: # specific list passed in objset = util.Set(objects) else: # or just everything objset = util.Set(self.identity_map.values()).union(self.new) # detect persistent objects that have changes dirty = self.locate_dirty() # store objects whose fate has been decided processed = util.Set() # put all saves/updates into the flush context. detect orphans and throw them into deleted. for obj in self.new.union(dirty).intersection(objset).difference(self.deleted): if obj in processed: continue if object_mapper(obj)._is_orphan(obj): for c in [obj] + list(object_mapper(obj).cascade_iterator('delete', obj)): if c in processed: continue flush_context.register_object(c, isdelete=True) processed.add(c) else: flush_context.register_object(obj) processed.add(obj) # put all remaining deletes into the flush context. for obj in self.deleted: if (objset is not None and not obj in objset) or obj in processed: continue flush_context.register_object(obj, isdelete=True) trans = session.create_transaction(autoflush=False) flush_context.transaction = trans try: flush_context.execute() except: trans.rollback() raise trans.commit() flush_context.post_exec()
def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, post_update_cols=None, **kwargs): """Add an object to this ``UOWTransaction`` to be updated in the database. This operation has the combined effect of locating/creating an appropriate ``UOWTask`` object, and calling its ``append()`` method which then locates/creates an appropriate ``UOWTaskElement`` object. """ #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) # if object is not in the overall session, do nothing if not self.uow._is_valid(obj): if logging.is_debug_enabled(self.logger): self.logger.debug("object %s not part of session, not registering for flush" % (mapperutil.instance_str(obj))) return if logging.is_debug_enabled(self.logger): self.logger.debug("register object for flush: %s isdelete=%s listonly=%s postupdate=%s" % (mapperutil.instance_str(obj), isdelete, listonly, postupdate)) mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) if postupdate: task.append_postupdate(obj, post_update_cols) return task.append(obj, listonly, isdelete=isdelete, **kwargs)
def __call__(self): if not mapper.has_identity(self.instance): return None localparent = mapper.object_mapper(self.instance, raiseerror=False) prop = localparent.get_property(self.key) strategy = prop._get_strategy(DeferredColumnLoader) if self.keys: toload = self.keys elif strategy.group: toload = [p.key for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group==strategy.group] else: toload = [self.key] # narrow the keys down to just those which have no history group = [k for k in toload if k in self.instance._state.unmodified] if strategy._should_log_debug: strategy.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(self.instance, self.key), group and ','.join(group) or 'None')) session = sessionlib.object_session(self.instance) if session is None: raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key)) query = session.query(localparent) if not self.optimizing_statement: ident = self.instance._instance_key[1] query._get(None, ident=ident, only_load_props=group, refresh_instance=self.instance._state) else: statement, params = self.optimizing_statement(self.instance) query.from_statement(statement).params(params)._get(None, only_load_props=group, refresh_instance=self.instance._state) return attributes.ATTR_WAS_SET
def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, post_update_cols=None, **kwargs): """Add an object to this UOWTransaction to be updated in the database. `isdelete` indicates whether the object is to be deleted or saved (update/inserted). `listonly` indicates that only this object's dependency relationships should be refreshed/updated to reflect a recent save/upcoming delete operation, but not a full save/delete operation on the object itself, unless an additional save/delete registration is entered for the object. """ #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) # if object is not in the overall session, do nothing if not self.uow._is_valid(obj): return mapper = object_mapper(obj) self.mappers.add(mapper) task = self.get_task_by_mapper(mapper) if postupdate: task.append_postupdate(obj, post_update_cols) return # for a cyclical task, things need to be sorted out already, # so this object should have already been added to the appropriate sub-task # can put an assertion here to make sure.... if task.circular: return task.append(obj, listonly, isdelete=isdelete, **kwargs)
def setup_loader(self, instance, options=None): if not mapper.has_mapper(instance): return None else: prop = mapper.object_mapper(instance).props[self.key] if prop is not self.parent_property: return prop._get_strategy(LazyLoader).setup_loader(instance) def lazyload(): self.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance))) params = {} allparams = True # if the instance wasnt loaded from the database, then it cannot lazy load # child items. one reason for this is that a bi-directional relationship # will not update properly, since bi-directional uses lazy loading functions # in both directions, and this instance will not be present in the lazily-loaded # results of the other objects since its not in the database if not mapper.has_identity(instance): return None #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds for col, bind in self.lazybinds.iteritems(): params[bind.key] = self.parent.get_attr_by_column(instance, col) if params[bind.key] is None: allparams = False break if not allparams: return None session = sessionlib.object_session(instance) if session is None: try: session = mapper.object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) # if we have a simple straight-primary key load, use mapper.get() # to possibly save a DB round trip if self.use_get: ident = [] for primary_key in self.select_mapper.pks_by_table[self.select_mapper.mapped_table]: bind = self.lazyreverse[primary_key] ident.append(params[bind.key]) return session.query(self.mapper).get(ident) elif self.order_by is not False: order_by = self.order_by elif self.secondary is not None and self.secondary.default_order_by() is not None: order_by = self.secondary.default_order_by() else: order_by = False result = session.query(self.mapper, with_options=options).select_whereclause(self.lazywhere, order_by=order_by, params=params) if self.uselist: return result else: if len(result): return result[0] else: return None return lazyload
def append(self, event, obj, item): # process "save_update" cascade rules for when an instance is appended to the list of another instance sess = object_session(obj) if sess is not None: if self.cascade is not None and self.cascade.save_update and item not in sess: mapper = object_mapper(obj) prop = mapper.props[self.key] ename = prop.mapper.entity_name sess.save_or_update(item, entity_name=ename)
def unregister_object(self, obj): """remove an object from its parent UOWTask. called by mapper.save_obj() when an 'identity switch' is detected, so that no further operations occur upon the instance.""" mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) if obj in task._objects: task.delete(obj)
def set(self, event, obj, newvalue, oldvalue): # process "save_update" cascade rules for when an instance is attached to another instance sess = object_session(obj) if sess is not None: if newvalue is not None and self.cascade is not None and self.cascade.save_update and newvalue not in sess: mapper = object_mapper(obj) prop = mapper.props[self.key] ename = prop.mapper.entity_name sess.save_or_update(newvalue, entity_name=ename)
def set(self, obj, newvalue, oldvalue, initiator): # process "save_update" cascade rules for when an instance is attached to another instance sess = object_session(obj) if sess is not None: if newvalue is not None and self.cascade is not None and self.cascade.save_update and newvalue not in sess: mapper = object_mapper(obj) prop = mapper.get_property(self.key) ename = prop.mapper.entity_name sess.save_or_update(newvalue, entity_name=ename)
def lazyload(): if self._should_log_debug: self.logger.debug( "lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance))) if not mapper.has_identity(instance): return None session = sessionlib.object_session(instance) if session is None: try: session = mapper.object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) # if we have a simple straight-primary key load, use mapper.get() # to possibly save a DB round trip q = session.query(self.mapper).autoflush(False) if self.use_get: params = {} for col, bind in self.lazybinds.iteritems(): params[bind.key] = self.parent.get_attr_by_column( instance, col) ident = [] nonnulls = False for primary_key in self.select_mapper.primary_key: bind = self.lazyreverse[primary_key] v = params[bind.key] if v is not None: nonnulls = True ident.append(v) if not nonnulls: return None if options: q = q.options(*options) return q.get(ident) elif self.order_by is not False: q = q.order_by(self.order_by) elif self.secondary is not None and self.secondary.default_order_by( ) is not None: q = q.order_by(self.secondary.default_order_by()) if options: q = q.options(*options) q = q.filter(self.lazy_clause(instance)) result = q.all() if self.uselist: return result else: if result: return result[0] else: return None
def unregister_object(self, obj): """remove an object from its parent UOWTask. called by mapper._save_obj() when an 'identity switch' is detected, so that no further operations occur upon the instance.""" mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) if obj._state in task._objects: task.delete(obj._state)
def lazyload(): if self._should_log_debug: self.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str( instance, self.key), str(self.group))) if not mapper.has_identity(instance): return None try: pk = self.parent.pks_by_table[self.columns[0].table] except KeyError: pk = self.columns[0].table.primary_key clause = sql.and_() for primary_key in pk: attr = self.parent.get_attr_by_column(instance, primary_key) if not attr: return None clause.clauses.append(primary_key == attr) session = sessionlib.object_session(instance) if session is None: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) localparent = mapper.object_mapper(instance) if self.group is not None: groupcols = [ p for p in localparent.props.values() if isinstance(p.strategy, DeferredColumnLoader) and p.group == self.group ] result = session.execute( localparent, sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None) try: row = result.fetchone() for prop in groupcols: if prop is self: continue # set a scalar object instance directly on the object, # bypassing SmartProperty event handlers. sessionlib.attribute_manager.init_instance_attribute( instance, prop.key, uselist=False) instance.__dict__[prop.key] = row[prop.columns[0]] return row[self.columns[0]] finally: result.close() else: return session.scalar( localparent, sql.select([self.columns[0]], clause, use_labels=True), None)
def append(self, obj, item, initiator): # process "save_update" cascade rules for when an instance is appended to the list of another instance sess = object_session(obj) if sess is not None: if self.cascade is not None and self.cascade.save_update and item not in sess: mapper = object_mapper(obj) prop = mapper.get_property(self.key) ename = prop.mapper.entity_name sess.save_or_update(item, entity_name=ename)
def __call__(self): instance = self.instance if not mapper.has_identity(instance): return None instance_mapper = mapper.object_mapper(instance) prop = instance_mapper.get_property(self.key) strategy = prop._get_strategy(LazyLoader) if strategy._should_log_debug: strategy.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance))) session = sessionlib.object_session(instance) if session is None: try: session = instance_mapper.get_session() except exceptions.InvalidRequestError: raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) q = session.query(prop.mapper).autoflush(False) if self.path: q = q._with_current_path(self.path) # if we have a simple primary key load, use mapper.get() # to possibly save a DB round trip if strategy.use_get: ident = [] allnulls = True for primary_key in prop.mapper.primary_key: val = instance_mapper._get_committed_attr_by_column(instance, strategy._equated_columns[primary_key]) allnulls = allnulls and val is None ident.append(val) if allnulls: return None if self.options: q = q._conditional_options(*self.options) return q.get(ident) if strategy.order_by is not False: q = q.order_by(strategy.order_by) elif strategy.secondary is not None and strategy.secondary.default_order_by() is not None: q = q.order_by(strategy.secondary.default_order_by()) if self.options: q = q._conditional_options(*self.options) q = q.filter(strategy.lazy_clause(instance)) result = q.all() if strategy.uselist: return result else: if result: return result[0] else: return None
def register_clean(self, obj): if obj in self.new: self.new.remove(obj) if not hasattr(obj, '_instance_key'): mapper = object_mapper(obj) obj._instance_key = mapper.instance_key(obj) if hasattr(obj, '_sa_insert_order'): delattr(obj, '_sa_insert_order') self.identity_map[obj._instance_key] = obj attribute_manager.commit(obj)
def register_clean(self, obj): """register the given object as 'clean' (i.e. persistent) within this unit of work.""" if obj in self.new: self.new.remove(obj) if not hasattr(obj, '_instance_key'): mapper = object_mapper(obj) obj._instance_key = mapper.instance_key(obj) if hasattr(obj, '_sa_insert_order'): delattr(obj, '_sa_insert_order') self.identity_map[obj._instance_key] = obj attribute_manager.commit(obj)
def _register_clean(self, obj): """register the given object as 'clean' (i.e. persistent) within this unit of work, after a save operation has taken place.""" if obj in self.new: self.new.remove(obj) if not hasattr(obj, '_instance_key'): mapper = object_mapper(obj) obj._instance_key = mapper.identity_key_from_instance(obj) if hasattr(obj, '_sa_insert_order'): delattr(obj, '_sa_insert_order') self.identity_map[obj._instance_key] = obj attribute_manager.commit(obj)
def object_was_deleted(session, obj): # hopefully there is a more future proof way to do this... from sqlalchemy.orm.mapper import object_mapper for c in [obj] + list( object_mapper(obj).cascade_iterator('delete', obj._state)): if c in session.deleted: return True # elif not session.uow._is_valid(c._state): # # it must have been deleted elsewhere. is there any other # # reason for this scenario? # return True return False
def _clone(self, sess=None): # note we're returning an entirely new Query class instance here # without any assignment capabilities; # the class of this query is determined by the session. instance = self.state.obj() if sess is None: sess = object_session(instance) if sess is None: try: sess = object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key)) return sess.query(self.attr.target_mapper).with_parent(instance)
def setup_loader(self, instance, options=None): if not mapper.has_mapper(instance): return None else: prop = mapper.object_mapper(instance).props[self.key] if prop is not self.parent_property: return prop._get_strategy(DeferredColumnLoader).setup_loader(instance) def lazyload(): if self._should_log_debug: self.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str(instance, self.key), str(self.group))) if not mapper.has_identity(instance): return None try: pk = self.parent.pks_by_table[self.columns[0].table] except KeyError: pk = self.columns[0].table.primary_key clause = sql.and_() for primary_key in pk: attr = self.parent.get_attr_by_column(instance, primary_key) if not attr: return None clause.clauses.append(primary_key == attr) session = sessionlib.object_session(instance) if session is None: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) localparent = mapper.object_mapper(instance) if self.group is not None: groupcols = [p for p in localparent.props.values() if isinstance(p.strategy, DeferredColumnLoader) and p.group==self.group] result = session.execute(localparent, sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None) try: row = result.fetchone() for prop in groupcols: if prop is self: continue # set a scalar object instance directly on the object, # bypassing SmartProperty event handlers. sessionlib.attribute_manager.init_instance_attribute(instance, prop.key, uselist=False) instance.__dict__[prop.key] = row[prop.columns[0]] return row[self.columns[0]] finally: result.close() else: return session.scalar(localparent, sql.select([self.columns[0]], clause, use_labels=True),None) return lazyload
def class_level_loader(self, instance, props=None): if not mapper.has_mapper(instance): return None localparent = mapper.object_mapper(instance) # adjust for the ColumnProperty associated with the instance # not being our own ColumnProperty. This can occur when entity_name # mappers are used to map different versions of the same ColumnProperty # to the class. prop = localparent.get_property(self.key) if prop is not self.parent_property: return prop._get_strategy(DeferredColumnLoader).setup_loader(instance) return LoadDeferredColumns(instance, self.key, props)
def class_level_loader(self, instance, options=None, path=None): if not mapper.has_mapper(instance): return None localparent = mapper.object_mapper(instance) # adjust for the PropertyLoader associated with the instance # not being our own PropertyLoader. This can occur when entity_name # mappers are used to map different versions of the same PropertyLoader # to the class. prop = localparent.get_property(self.key) if prop is not self.parent_property: return prop._get_strategy(LazyLoader).setup_loader(instance) return LoadLazyAttribute(instance, self.key, options, path)
def __init__(self, obj): self.columns = obj.c self.id_attr = obj.id.key from sqlalchemy.orm.mapper import object_mapper # is this safe? self.mapper = object_mapper(obj()) if self.mapper.local_table: self.table = self.mapper.local_table elif self.mapper.select_table: self.table = self.mapper.select_table else: raise LookupError( "not sure how to get a table from mapper %s" % self.mapper)
def __init__(self, obj): self.columns = obj.c # could grab this from the Handler : from sqlalchemy.orm.mapper import object_mapper self.mapper = object_mapper(obj()) if self.mapper.local_table: self.table = self.mapper.local_table elif self.mapper.select_table: self.table = self.mapper.select_table else: raise LookupError( "not sure how to get a table from mapper %s" % self.mapper) self.id_attr = self.table.primary_key.columns.keys()
def _clone(self, sess=None): # note we're returning an entirely new Query class instance here # without any assignment capabilities; # the class of this query is determined by the session. instance = self.instance if sess is None: sess = object_session(instance) if sess is None: try: sess = object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (mapperutil.instance_str(instance), self.attr.key)) q = sess.query(self.attr.target_mapper).with_parent(instance, self.attr.key) if self.attr.order_by: q = q.order_by(self.attr.order_by) return q
def register_object(self, obj, isdelete=False, listonly=False, postupdate=False, post_update_cols=None, **kwargs): """Add an object to this UOWTransaction to be updated in the database. `isdelete` indicates whether the object is to be deleted or saved (update/inserted). `listonly` indicates that only this object's dependency relationships should be refreshed/updated to reflect a recent save/upcoming delete operation, but not a full save/delete operation on the object itself, unless an additional save/delete registration is entered for the object. """ #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) # if object is not in the overall session, do nothing if not self.uow._is_valid(obj): return mapper = object_mapper(obj) self.mappers.add(mapper) task = self.get_task_by_mapper(mapper) if postupdate: task.append_postupdate(obj, post_update_cols) return # for a cyclical task, things need to be sorted out already, # so this object should have already been added to the appropriate sub-task # can put an assertion here to make sure.... if task.circular: return task.append(obj, listonly, isdelete=isdelete, **kwargs)
def register_object(self, obj, isdelete=False, listonly=False, postupdate=False, post_update_cols=None, **kwargs): """Add an object to this ``UOWTransaction`` to be updated in the database. This operation has the combined effect of locating/creating an appropriate ``UOWTask`` object, and calling its ``append()`` method which then locates/creates an appropriate ``UOWTaskElement`` object. """ #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) # if object is not in the overall session, do nothing if not self.uow._is_valid(obj): if self._should_log_debug: self.logger.debug( "object %s not part of session, not registering for flush" % (mapperutil.instance_str(obj))) return if self._should_log_debug: self.logger.debug( "register object for flush: %s isdelete=%s listonly=%s postupdate=%s" % (mapperutil.instance_str(obj), isdelete, listonly, postupdate)) mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) if postupdate: task.append_postupdate(obj, post_update_cols) return task.append(obj, listonly, isdelete=isdelete, **kwargs)
def keyfunc(value): m = mapper.object_mapper(value) return tuple( [m.get_attr_by_column(value, c) for c in mapping_spec])
def keyfunc(value): m = mapper.object_mapper(value) return m.get_attr_by_column(value, mapping_spec)
def unregister_object(self, obj): #print "UNREGISTER", obj mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) if obj in task.objects: task.delete(obj)
def flush(self, session, objects=None): """create a dependency tree of all pending SQL operations within this unit of work and execute.""" # this context will track all the objects we want to save/update/delete, # and organize a hierarchical dependency structure. it also handles # communication with the mappers and relationships to fire off SQL # and synchronize attributes between related objects. # detect persistent objects that have changes dirty = self.locate_dirty() if len(dirty) == 0 and len(self.deleted) == 0 and len(self.new) == 0: return flush_context = UOWTransaction(self, session) if session.extension is not None: session.extension.before_flush(session, flush_context, objects) # create the set of all objects we want to operate upon if objects is not None: # specific list passed in objset = util.Set(objects) else: # or just everything objset = util.Set(self.identity_map.values()).union(self.new) # store objects whose fate has been decided processed = util.Set() # put all saves/updates into the flush context. detect top-level orphans and throw them into deleted. for obj in self.new.union(dirty).intersection(objset).difference( self.deleted): if obj in processed: continue flush_context.register_object( obj, isdelete=object_mapper(obj)._is_orphan(obj)) processed.add(obj) # put all remaining deletes into the flush context. for obj in self.deleted.intersection(objset).difference(processed): flush_context.register_object(obj, isdelete=True) if len(flush_context.tasks) == 0: return session.create_transaction(autoflush=False) flush_context.transaction = session.transaction try: flush_context.execute() if session.extension is not None: session.extension.after_flush(session, flush_context) except: session.rollback() raise session.commit() flush_context.post_exec() if session.extension is not None: session.extension.after_flush_postexec(session, flush_context)
def is_deleted(self, obj): mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) return task.is_deleted(obj)
def is_deleted(self, obj): """return true if the given object is marked as deleted within this UOWTransaction.""" mapper = object_mapper(obj) task = self.get_task_by_mapper(mapper) return task.is_deleted(obj)
def _target_mapper(self, obj): prop = object_mapper(obj).get_property(self.key) return prop.mapper
def lazyload(): self.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance))) params = {} allparams = True # if the instance wasnt loaded from the database, then it cannot lazy load # child items. one reason for this is that a bi-directional relationship # will not update properly, since bi-directional uses lazy loading functions # in both directions, and this instance will not be present in the lazily-loaded # results of the other objects since its not in the database if not mapper.has_identity(instance): return None #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds for col, bind in self.lazybinds.iteritems(): params[bind.key] = self.parent.get_attr_by_column( instance, col) if params[bind.key] is None: allparams = False break if not allparams: return None session = sessionlib.object_session(instance) if session is None: try: session = mapper.object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) # if we have a simple straight-primary key load, use mapper.get() # to possibly save a DB round trip if self.use_get: ident = [] for primary_key in self.select_mapper.pks_by_table[ self.select_mapper.mapped_table]: bind = self.lazyreverse[primary_key] ident.append(params[bind.key]) return session.query(self.mapper).get(ident) elif self.order_by is not False: order_by = self.order_by elif self.secondary is not None and self.secondary.default_order_by( ) is not None: order_by = self.secondary.default_order_by() else: order_by = False result = session.query(self.mapper, with_options=options).select_whereclause( self.lazywhere, order_by=order_by, params=params) if self.uselist: return result else: if len(result): return result[0] else: return None
def setup_loader(self, instance, props=None, create_statement=None): localparent = mapper.object_mapper(instance, raiseerror=False) if localparent is None: return None # adjust for the ColumnProperty associated with the instance # not being our own ColumnProperty. This can occur when entity_name # mappers are used to map different versions of the same ColumnProperty # to the class. prop = localparent.get_property(self.key) if prop is not self.parent_property: return prop._get_strategy(DeferredColumnLoader).setup_loader( instance) def lazyload(): if not mapper.has_identity(instance): return None if props is not None: group = props elif self.group is not None: group = [ p for p in localparent.iterate_properties if isinstance(p.strategy, DeferredColumnLoader) and p.group == self.group ] else: group = [self.parent_property] if self._should_log_debug: self.logger.debug( "deferred load %s group %s" % (mapperutil.attribute_str(instance, self.key), group and ','.join([p.key for p in group]) or 'None')) session = sessionlib.object_session(instance) if session is None: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) if create_statement is None: (clause, param_map) = localparent._get_clause ident = instance._instance_key[1] params = {} for i, primary_key in enumerate(localparent.primary_key): params[param_map[primary_key].key] = ident[i] statement = sql.select([p.columns[0] for p in group], clause, from_obj=[localparent.mapped_table], use_labels=True) else: statement, params = create_statement() # TODO: have the "fetch of one row" operation go through the same channels as a query._get() # deferred load of several attributes should be a specialized case of a query refresh operation conn = session.connection(mapper=localparent, instance=instance) result = conn.execute(statement, params) try: row = result.fetchone() for prop in group: sessionlib.attribute_manager.set_committed_value( instance, prop.key, row[prop.columns[0]]) return attributes.ATTR_WAS_SET finally: result.close() return lazyload