2013-03-26 30 views
5

Il problema è che non riesco a capire come usare SQLAlchemy per avvisarmi quando un oggetto entra in un nuovo stato.Come posso ottenere lo stato precedente di un oggetto ORM SQLAlchemy dopo un aggiornamento db?

sto usando SQLAlchemy ORM (dichiarativa) per aggiornare un oggetto:

class Customer(declarative_base()): 

    __table_name__ = "customer" 

    id = Column(Integer, primary_key=True) 
    status = Column(String) 

Voglio sapere quando un oggetto entra in uno stato. Soprattutto dopo che è stato emesso un UPDATE e quando lo stato cambia. Per esempio. Customer.status == 'registered' e in precedenza aveva uno stato diverso.

Attualmente sto facendo questo con un evento attributo 'set':

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) 

Il mio codice spara ogni volta 'set' è chiamato a quell'attributo, e io verificare se il value e la oldvalue sono diversi. Il problema è che il parametro target non è completamente formato quindi non ha ancora tutti i valori di attributo popolati.

C'è un modo migliore per farlo? Grazie!

risposta

10

La mia soluzione era usare 'after_flush' SessionEvent invece di 'set' AttributeEvent.

Mille grazie a agronholm che ha fornito un esempio di codice SessionEvent che ha verificato in modo specifico il valore di un oggetto e il valore vecchio.

La soluzione qui di seguito è una modifica del suo codice:

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) 

Il registry è un dizionario le cui chiavi sono MapperProperty e la cui valori sono i gestori di eventi. session, event, inspect e object_mapper sono tutte le classi e le funzioni sqlalchemy.

Problemi correlati