2015-04-28 4 views
9

Я хочу регистрировать каждое действие, что будет сделано с некоторыми SQLAlchemy-Models.Отслеживание изменений модели в SQLAlchemy

Итак, у меня есть after_insert, after_delete и before_update крючки, где я спасу предыдущее и текущее представление модели,

def keep_logs(cls): 
    @event.listens_for(cls, 'after_delete') 
    def after_delete_trigger(mapper, connection, target): 
     pass 

    @event.listens_for(cls, 'after_insert') 
    def after_insert_trigger(mapper, connection, target): 
     pass 

    @event.listens_for(cls, 'before_update') 
    def before_update_trigger(mapper, connection, target): 
     prev = cls.query.filter_by(id=target.id).one() 
     # comparing previous and current model 


MODELS_TO_LOGGING = (
    User, 
) 
for cls in MODELS_TO_LOGGING: 
    keep_logs(cls) 

Но есть одна проблемы: когда я пытаюсь найти модель в before_update hook, SQLA возвращает измененную (грязную) версию. Как я могу получить предыдущую версию модели перед ее обновлением? Есть ли другой способ сохранить изменения модели?

Спасибо!

ответ

9

SQLAlchemy отслеживает изменения каждого атрибута. Вам не нужно (и не должно) запрашивать экземпляр снова в событии. Кроме того, событие запускается для любого экземпляра, который был изменен, даже если эта модификация не изменит никаких данных. Перебирайте каждый столбец, проверяя, был ли он изменен, и сохраняйте любые новые значения.

@event.listens_for(cls, 'before_update') 
def before_udpate(mapper, connection, target): 
    state = db.inspect(target) 
    changes = {} 

    for attr in state.attrs: 
     hist = state.get_history(attr.key, True) 

     if not hist.has_changes(): 
      continue 

     # hist.deleted holds old value 
     # hist.added holds new value 
     changes[attr.key] = hist.added 

    # now changes map keys to new values