Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何检查SQLAlchemy会话是否脏_Python_Sqlalchemy - Fatal编程技术网

Python 如何检查SQLAlchemy会话是否脏

Python 如何检查SQLAlchemy会话是否脏,python,sqlalchemy,Python,Sqlalchemy,我有一个SQLAlchemy会话对象,想知道它是否脏。我想(隐喻性地)问会话的确切问题是:“如果此时我发出commit()或rollback(),对数据库的影响是否相同?” 其基本原理是:我想询问用户是否希望确认更改。但如果没有变化,我不想问任何问题。当然,我可以监控自己在会话上执行的所有操作,并决定是否有修改,但由于我的程序结构,这需要一些非常复杂的更改。如果SQLAlchemy已经提供了这个机会,我很乐意利用它 谢谢大家。会话有一个私有的\u is\u clean()成员,如果没有要刷新到数

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

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


谢谢大家。

会话有一个私有的
\u is\u clean()
成员,如果没有要刷新到数据库的内容,该成员似乎会返回true。然而,它是私有的这一事实可能意味着它不适合外部使用。我个人不建议这样做,因为这里的任何错误都可能导致用户的数据丢失。

会话具有肮脏属性

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


您正在查找会话事务整个期间进行的实际刷新的净计数;虽然有一些线索表明是否发生了这种情况(称为“快照”),但这种结构只是为了帮助回滚,而不是强引用。最直接的途径是跟踪“after_flush”事件,因为此事件仅在调用flush并且flush found状态为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)

以下是我根据@zzzeek的回答和最新评论提出的解决方案。我已经对它进行了单元测试,它似乎可以很好地进行回滚(发出回滚后会话是干净的):


这并不能解决我的问题:可能没有脏对象,但是如果一些更改已经刷新到数据库中,我仍然想知道。除了私有的事实之外,它显然与Yoriz的回答有相同的问题:我想检测已经刷新但未提交的更改。嗯,好的。除了在SQLAlchemy组()上发布之外,我没有任何其他建议,如果您得到答案,请在这里发布。我在一年半后注意到这个答案。。。谢谢,这正是我需要的。我通过添加另一个检查对其进行了增强:只有在
会话中有内容时,才使用刷新将事务实际添加到
事务中。新建
会话。删除
会话。脏
。此外,
session.dirty
中的对象首先使用
session.is\u modified
进行测试。最终实施在矿山的本项目中:。虽然我没有执行疯狂的测试,但它似乎有效。
\u iterate\u parents
已从SQLAlchemy中删除。现在父迭代必须手工完成。查看上面相同的链接以查看我的实现,它似乎可以工作。这个答案很奇怪。会话最近有一个.Info字典。在after_flush中放入“flush=True”,并在after_commit中删除它。我不知道为什么我要把所有SessionTransaction对象放在字典里。@zzzeek这对回滚很好,还是我们也需要为这些对象在
之后挂接
?请用info dict方法更新您的答案好吗?@rdrey提交/回滚独立于flush()。上面的方法还将告诉您是否已刷新数据,该数据也会受到rollback()的影响。
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)