如何检查SQLAlchemy会话是否脏

时间:2013-04-27 20:54:09

标签: python sqlalchemy

我有一个SQLAlchemy Session对象,想知道它是否脏。我想(隐喻地)询问Session的确切问题是:“如果此时我发出commit()rollback(),对数据库的影响是相同的或者不?”。

理由是这样的:我想询问用户是否想要确认更改。但如果没有变化,我不想问任何问题。当然,我可以监视自己在Session上执行的所有操作,并决定是否有修改,但由于我的程序结构,这需要一些相关的更改。如果SQLAlchemy已经提供了这个机会,我很乐意利用它。

谢谢大家。

4 个答案:

答案 0 :(得分:12)

您正在寻找在会话交易的整个范围内进行的实际刷新的净计数;虽然有一些关于这是否发生的线索(称为“快照”),但这种结构只是为了帮助回滚,而不是强引用。最直接的方法是跟踪“after_flush”事件,因为此事件仅在调用flush时发出,并且flush发现状态为flush:

from sqlalchemy import event
import weakref
transactions_with_flushes = weakref.WeakSet()

@event.listens_for(Session, "after_flush")
def log_transaction(session, flush_context):
    for trans in session.transaction._iterate_parents():
        transactions_with_flushes.add(trans)

def session_has_pending_commit(session):
    return session.transaction in transactions_with_flushes

编辑:这是一个更简单的更新版本:

from sqlalchemy import event

@event.listens_for(Session, "after_flush")
def log_transaction(session, flush_context):
    session.info['has_flushed'] = True

def session_has_pending_commit(session):
    return session.info.get('has_flushed', False)

答案 1 :(得分:2)

会话具有脏属性

session.dirty

当前检测到更改的持久对象 (现在,每次调用属性时都会动态创建此集合)

sqlalchemy.orm.session.Session.dirty

答案 2 :(得分:1)

以下是基于@ zzzeek的回答和更新评论的解决方案。我已经对它进行了单元测试,它似乎与回滚相匹配(发布回滚后会话是干净的):

from sqlalchemy import event
from sqlalchemy.orm import Session


@event.listens_for(Session, "after_flush")
def log_flush(session, flush_context):
    session.info['flushed'] = True


@event.listens_for(Session, "after_commit")
@event.listens_for(Session, "after_rollback")
def reset_flushed(session):
    if 'flushed' in session.info:
        del session.info['flushed']


def has_uncommitted_changes(session):
    return any(session.new) or any(session.deleted) \
        or any([x for x in session.dirty if session.is_modified(x)]) \
        or session.info.get('flushed', False)

答案 3 :(得分:0)

会话有一个私有_is_clean()成员,如果没有要刷新到数据库的内容,它似乎返回true。但是,它是私人的这一事实可能意味着它不适合外部使用。我没有亲自推荐这个,因为这里的任何错误都可能导致用户数据丢失。