The issue is that I can't figure out how to use SQLAlchemy to notify me when an object goes into a new state.
I'm using SQLAlchemy ORM (Declarative) to update an object:
class Customer(declarative_base()):
__table_name__ = "customer"
id = Column(Integer, primary_key=True)
status = Column(String)
I want to know when an object enters a state. Particularly after an UPDATE has been issued and when the state changes. E.g. Customer.status == 'registered'
and it previously had a different state.
I'm currently doing this with an 'set'
attribute event:
from sqlalchemy import event
from model import Customer
def on_set_attribute(target, value, oldvalue, initiator):
print target.status
print value
print oldvalue
event.listen(
Customer.status,
'set',
on_set_attribute,
propagate=True,
active_history=True)
My code fires every time 'set' is called on that attribute, and I check if the value
and the oldvalue
are different. The problem is that the target
parameter isn't fully formed so it doesn't have all the attribute values populated yet.
Is there a better way to do this? Thanks!
Update table elements in SQLAlchemy. Get the books to table from the Metadata object initialized while connecting to the database. Pass the update query to the execute() function and get all the results using fetchall() function. Use a for loop to iterate through the results.
It returns an instance based on the given primary key identifier providing direct access to the identity map of the owning Session. It creates a SQL JOIN against this Query object's criterion and apply generatively, returning the newly resulting Query. It returns exactly one result or raise an exception.
_sa_instance_state is a non-database-persisted value used by SQLAlchemy internally (it refers to the InstanceState for the instance.
My solution was to use 'after_flush' SessionEvent instead of 'set' AttributeEvent.
Many thanks to agronholm who provided example SessionEvent code that specifically checked an object's value and oldvalue.
The solution below is a modification of his code:
def get_old_value(attribute_state):
history = attribute_state.history
return history.deleted[0] if history.deleted else None
def trigger_attribute_change_events(object_):
for mapper_property in object_mapper(object_).iterate_properties:
if isinstance(mapper_property, ColumnProperty):
key = mapper_property.key
attribute_state = inspect(object_).attrs.get(key)
history = attribute_state.history
if history.has_changes():
value = attribute_state.value
# old_value is None for new objects and old value for dirty objects
old_value = get_old_value(attribute_state)
handler = registry.get(mapper_property)
if handler:
handler(object_, value, old_value)
def on_after_flush(session, flush_context):
changed_objects = session.new.union(session.dirty)
for o in changed_objects:
trigger_attribute_change_events(o)
event.listen(session, "after_flush", on_after_flush)
The registry
is a dictionary whose keys are MapperProperty's and whose values are event handlers.
session
, event
, inspect
, and object_mapper
are all sqlalchemy classes and functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With