I have a SQLAlchemy Session
object and would like to know whether it is dirty or not. The exact question what I would like to (metaphorically) ask the Session
is: "If at this point I issue a commit()
or a rollback()
, the effect on the database is the same or not?".
我有一个SQLAlchemy会话对象,想知道它是否脏。我想(隐喻地)问这个会话的确切问题是:“如果此时我发出commit()或rollback(),那么对数据库的影响是否相同?”
The rationale is this: I want to ask the user wether he wants or not to confirm the changes. But if there are no changes, I would like not to ask anything. Of course I may monitor myself all the operations that I perform on the Session
and decide whether there were modifications or not, but because of the structure of my program this would require some quite involved changes. If SQLAlchemy already offered this opportunity, I'd be glad to take advantage of it.
基本原理是:我想询问用户是否想要确认更改。但如果没有变化,我也不想问什么。当然,我可以监视我在会话上执行的所有操作并决定是否有修改,但是由于我的程序的结构,这将需要一些相当复杂的修改。如果SQLAlchemy已经提供了这个机会,我很乐意利用它。
Thanks everybody.
谢谢大家。
4 个解决方案
#1
10
you're looking for a net count of actual flushes that have proceeded for the whole span of the session's transaction; while there are some clues to whether or not this has happened (called the "snapshot"), this structure is just to help with rollbacks and isn't strong referencing. The most direct route to this would be to track "after_flush" events, since this event only emits if flush were called and also that the flush found state to flush:
你要寻找的是在整个交易过程中进行的实际冲量的净计数;虽然有一些线索可以判断这种情况是否已经发生(称为“快照”),但是这种结构只是为了帮助回滚,并不是很好的引用。最直接的路径是跟踪“after_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
edit: here's an updated version that's a lot simpler:
编辑:这里有一个更简单的更新版本:
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)
#2
2
The session has a dirty attribute
会话有一个脏属性。
session.dirty
persistent objects which currently have changes detected (this collection is now created on the fly each time the property is called)
当前检测到更改的持久对象(每次调用属性时都动态创建此集合)
sqlalchemy.orm.session.Session.dirty
sqlalchemy.orm.session.Session.dirty
#3
0
Sessions have a private _is_clean()
member which seems to return true if there is nothing to flush to the database. However, the fact that it is private may mean it's not suitable for external use. I'd stop short of personally recommending this, since any mistake here could obviously result in data loss for your users.
会话有一个私有的_is_clean()成员,如果没有什么要刷新到数据库的内容,这个成员似乎返回true。然而,它是私有的这一事实可能意味着它不适合外部使用。我不打算亲自推荐它,因为这里的任何错误都可能导致用户的数据丢失。
#4
0
Here is my solution based on @zzzeek's answer and updated comment. I've unit tested it and it seems to play well with rollbacks (a session is clean after issuing a rollback):
这是我的解决方案,基于@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)
#1
10
you're looking for a net count of actual flushes that have proceeded for the whole span of the session's transaction; while there are some clues to whether or not this has happened (called the "snapshot"), this structure is just to help with rollbacks and isn't strong referencing. The most direct route to this would be to track "after_flush" events, since this event only emits if flush were called and also that the flush found state to flush:
你要寻找的是在整个交易过程中进行的实际冲量的净计数;虽然有一些线索可以判断这种情况是否已经发生(称为“快照”),但是这种结构只是为了帮助回滚,并不是很好的引用。最直接的路径是跟踪“after_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
edit: here's an updated version that's a lot simpler:
编辑:这里有一个更简单的更新版本:
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)
#2
2
The session has a dirty attribute
会话有一个脏属性。
session.dirty
persistent objects which currently have changes detected (this collection is now created on the fly each time the property is called)
当前检测到更改的持久对象(每次调用属性时都动态创建此集合)
sqlalchemy.orm.session.Session.dirty
sqlalchemy.orm.session.Session.dirty
#3
0
Sessions have a private _is_clean()
member which seems to return true if there is nothing to flush to the database. However, the fact that it is private may mean it's not suitable for external use. I'd stop short of personally recommending this, since any mistake here could obviously result in data loss for your users.
会话有一个私有的_is_clean()成员,如果没有什么要刷新到数据库的内容,这个成员似乎返回true。然而,它是私有的这一事实可能意味着它不适合外部使用。我不打算亲自推荐它,因为这里的任何错误都可能导致用户的数据丢失。
#4
0
Here is my solution based on @zzzeek's answer and updated comment. I've unit tested it and it seems to play well with rollbacks (a session is clean after issuing a rollback):
这是我的解决方案,基于@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)