How can I get a SQLAlchemy ORM object's previous state after a db update?

一个人想着一个人 提交于 2019-12-04 23:54:08

问题


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!


回答1:


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.




回答2:


use the before_update event or the before_flush event to intercept this happening at a later point in time.



来源:https://stackoverflow.com/questions/15642286/how-can-i-get-a-sqlalchemy-orm-objects-previous-state-after-a-db-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!