跟踪SQLAlchemy中的模型更改

时间:2015-04-28 13:42:10

标签: python sqlalchemy unit-of-work

我想记录一些SQLAlchemy-Models将要完成的操作。

所以,我有一个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钩子中找到模型时,SQLA返回修改(脏)版本。 如何在更新之前获取以前版本的模型? 是否有不同的方法来保持模型更改?

谢谢!

3 个答案:

答案 0 :(得分:19)

SQLAlchemy跟踪每个属性的更改。您不需要(并且不应该)在事件中再次查询实例。此外,即使该修改不会更改任何数据,也会针对已修改的任何实例触发事件。循环遍历每一列,检查它是否已被修改,并存储任何新值。

// Doubly linked list

#include <stdio.h>

struct entry
    {
        int value;
        struct entry *next;
        struct entry *prev;
    };

void dubbleNext (struct entry *e) {
    if (e != '\0') {
        printf ("%d\n", e->value);
        dubbleNext(e->next);
    }
}

void dubblePrev (struct entry *e) {
    if (e != '\0') {
        printf ("%d\n", e->value);
        dubbleNext(e->prev);
    }
}

int main (void)
{


    struct entry n1, n2, n3;
    int i;

    n1.value = 100;
    n2.value = 200;
    n3.value = 300;

    n1.next = &n2;
    n2.next = &n3;
    n3.next = NULL;

    n1.prev = NULL;
    n2.prev = &n1;
    n3.prev = &n2;

    dubbleNext (&n1);
    dubblePrev (&n3);

    return 0;
}

答案 1 :(得分:1)

我无法发表评论,但要解决大卫所回答的问题:

如果某个属性已过期(默认情况下会在提交时执行哪些会话),则除非在更改之前加载旧值,否则旧值不可用。您可以通过检查看到这一点。

state = inspect(entity)
session.commit()
state.attrs.my_attribute.history  # History(added=None, unchanged=None, deleted=None)
# Load history manually
state.attrs.my_attribute.load_history()
state.attrs.my_attribute.history  # History(added=(), unchanged=['my_value'], deleted=())

为了使属性保持加载状态,您无法通过会话expire_on_commit将实体到期为False。

答案 2 :(得分:0)

我有一个类似的问题,但是我希望能够跟踪增量,因为对sqlalchemy模型进行了更改,而不仅仅是更改了新值。我为davidism's答案写了这个扩展名,以达到更好的处理barbefore的目的,因为有时它们是列表或空元组:

after