Reputation: 494
I am able to use sqlalchemy's inspect function to find the history of a specific model, for any normal value. However, when I attempt to get the history for a relationship (or its related ForeignKey column), it only shows the new value, not the previous value.
Is there any quick way to get the previous value of a relationship like this, or do I need to use another function, or completely roll my own?
Basic code I am using looks like
class Person(db.Model):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80))
phone_id = db.Column(db.Integer(), db.ForeignKey("phone_number.id"))
phone = db.relationship("PhoneNumber")
class PhoneNumber(db.Model):
id = db.Column(db.Integer(), primary_key = True)
type = db.Column(db.String(20))
number = db.Column(db.String(11))
p = Person()
p.name = "Frank"
phone1 = PhoneNumber("Mobile", "1234567890") #__init__ function handles these args
phone2 = PhoneNumber("Home", "9876543210")
p.phone = phone1
db.session.add_all([p, phone1, phone2])
db.session.commit()
p.phone = phone2
history = db.inspect(p).attrs.get("phone").history
# history is sqlalchemy.orm.attributes.History(([<PhoneNumber('Home', '9876543210')>], (), ()))
# history.added is ([<PhoneNumber('Home', '9876543210')>])
# history.deleted is () but should be ([<PhoneNumber('Mobile', '1234567890')>])
Upvotes: 4
Views: 1663
Reputation: 75117
the "old" value of a scalar attribute is usually not loaded from the database if not present already, as this is typically wasteful (in this case, session.commit() expires all attributes, so Person.phone is unloaded when the new value is assigned). Exceptions include when the column is a primary key column, or for a scalar relationship with something other than a simple many-to-one. This loading of the "old" value can be forced by using the "active_history" option on the attribute in question.
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer(), primary_key=True)
name = Column(String(80))
phone_id = Column(Integer(), ForeignKey("phone_number.id"))
phone = relationship("PhoneNumber", active_history=True)
class PhoneNumber(Base):
__tablename__ = 'phone_number'
id = Column(Integer(), primary_key=True)
type = Column(String(20))
number = Column(String(11))
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
session = Session(e)
p = Person()
p.name = "Frank"
phone1 = PhoneNumber(type="Mobile", number="1234567890")
phone2 = PhoneNumber(type="Home", number="9876543210")
p.phone = phone1
session.add_all([p, phone1, phone2])
session.commit()
p.phone = phone2
history = inspect(p).attrs.get("phone").history
assert history == ([phone2], (), [phone1])
Upvotes: 5