What exactly causes the session to flush? I'm trying to track down a nasty bug in my versioning system.
Sorry for the long code dump. I retooled examples/versioned_history/history_meta.py so it should look familiar. The function that's breaking is "column_has_changed". I've added some logs as well. # WHEN IT WORKS! CRITICAL:root:BEFORE MAPPING NEW VALUES CRITICAL:root:BEFORE SAVE CRITICAL:root:BEFORE REVISE CRITICAL:root:CHECK COLUMN CHANGES CRITICAL:root:AFTER REVISE CRITICAL:root:flush! CRITICAL:root:AFTER SAVE CRITICAL:root:flush! # WHEN IT DOESN'T WORK! CRITICAL:root:BEFORE MAPPING NEW VALUES CRITICAL:root:BEFORE SAVE CRITICAL:root:BEFORE REVISE CRITICAL:root:flush! CRITICAL:root:CHECK COLUMN CHANGES CRITICAL:root:AFTER REVISE CRITICAL:root:AFTER SAVE CRITICAL:root:flush! controller.py for k, v in dict.items(): setattr(model, k, v) model.revise() db.session.add(model) db.session.commit() model.py class RevisionMixin: """Version control manager.""" def revise(self): db.session.add(self) write_revision(self) version.py def write_revision(target): target_mapper = orm.object_mapper(target) revision_class = target.__versioned__['model'] revision_mapper = revision_class.__mapper__ object_changed = False state = {} for column in iter_mapper_columns(target_mapper, revision_mapper): state[column.key] = getattr(target, column.key) column_changed = column_has_changed(target, column.key) object_changed = object_changed or column_changed for relationship, changed in iter_relationships(target, target_mapper): if hasattr(revision_class, relationship.key): state[relationship.key] = getattr(target, relationship.key) object_changed = object_changed or changed if not isinstance(target.id, str) or object_changed: _write_revision(target, state) def _write_revision(target, state): version = target.version or 0 version = version + 1 state['version'] = version state['updated_at'] = db.now() state['primary'] = target revision = target.__versioned__['model'](**state) db.session.add(revision) target.version = version target.updated_at = state['updated_at'] def iter_mapper_columns(primary, revision): mappers = zip(primary.iterate_to_root(), revision.iterate_to_root()) for om, hm in mappers: if hm.single: continue for column in iter_shared_columns(om, hm): yield column def iter_shared_columns(mapper, comparison_mapper): for comparison_mapper_column in comparison_mapper.local_table.c: if 'version_meta' in comparison_mapper_column.info: continue try: mapper_column = mapper.local_table.c[comparison_mapper_column. key] yield mapper.get_property_by_column(mapper_column) except UnmappedColumnError: continue def iter_relationships(target, mapper): for prop in mapper.iterate_properties: if isinstance(prop, RelationshipProperty): passive = attributes.PASSIVE_NO_INITIALIZE changed = attributes.get_history( target, prop.key, passive=passive).has_changes() yield prop, changed def column_has_changed(target, column_name): # Sometimes the instance state history can't be properly # calculated? No flushing during versioning. Unsure why its not # working. added, _, deleted = attributes.get_history(target, column_name) return bool(added or deleted) def relationship_has_changed(prop): for p in prop.local_columns: if p.foreign_keys: return True return False -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.