- edited description
Attribute history not tracked when using session.merge()
I've noticed that the attribute history of my objects is not tracked. The object comes from session.merge() like it was just freshly retrieved from database.
shipping_id = int(request.matchdict.get('id'))
# Get model from db
db_shipping = db.session.query(m.Shipping).get(shipping_id)
# Create updated instance
updated_shipping = m.Shipping(id=shipping_id, price=999)
# Merge it with session
merged = db.session.merge(updated_shipping)
# I've noticed an actual UPDATE is emitted at this point
# Attributes values are correctly reflected, but the history is all 'unchanged'
# Simply iterates over history of each attribute
changeset(merged)
# History is all 'unchanged'
From the other hand, if I add one line, this works:
shipping_id = int(request.matchdict.get('id'))
# Get model from db
db_shipping = db.session.query(m.Shipping).get(shipping_id)
# When I add this, the history is tracked properly
changeset(db_shipping)
# Create updated instance
updated_shipping = m.Shipping(id=shipping_id, price=999)
# Merge it with session
merged = db.session.merge(updated_shipping)
# Attributes values are correctly reflected, history state is correct
# Simply iterates over history of each attribute
changeset(merged)
def changeset(obj):
data = {}
for prop in obj.__mapper__.iterate_properties:
history = get_history(obj, prop.key)
if history.has_changes():
old_value = history.deleted[0] if history.deleted else None
new_value = history.added[0] if history.added else None
if new_value:
data[prop.key] = [new_value, old_value]
return data
Comments (5)
-
reporter -
repo owner Hi there -
there's not enough detail to show anything here, no data, no mappings. Here is a demo using your function:
from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.attributes import get_history Base = declarative_base() def changeset(obj): data = {} for prop in obj.__mapper__.iterate_properties: history = get_history(obj, prop.key) if history.has_changes(): old_value = history.deleted[0] if history.deleted else None new_value = history.added[0] if history.added else None if new_value: data[prop.key] = [new_value, old_value] return data class A(Base): __tablename__ = 'a' id = Column(Integer, primary_key=True) x = Column('x', Integer) y = Column('y', Integer) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add(A(x=1, y=2)) s.commit() s.close() a1 = s.query(A).first() # When I add this, the history is tracked properly # changeset(db_shipping) # Create updated instance new_a = A(id=a1.id, x=45, y=4) # Merge it with session merged = s.merge(new_a) # Attributes values are correctly reflected, history state is correct # Simply iterates over history of each attribute print(changeset(merged))
output:
#! {u'y': [4, 2], u'x': [45, 1]}
-
repo owner - changed status to on hold
please provide a complete example that I can run locally here, see http://sscce.org/ for guidelines, thanks!
-
repo owner - changed status to closed
hi there -
I don't doubt that you might be hitting something erroneous but I'd need a complete test script to continue. please reopen if you're able to provide this thanks!
-
reporter I'm using SqlAlchemy with Pyramid and transaction manager, so maybe there is something about the ecosystem. As soon as I'll get back to this issue I'll try to create better example.
- Log in to comment