停止 SQLAlchemy 更新已从数据库中提取的行

Posted

技术标签:

【中文标题】停止 SQLAlchemy 更新已从数据库中提取的行【英文标题】:Stop SQLAlchemy from updating rows that have already been pulled from the database 【发布时间】:2013-07-02 21:11:44 【问题描述】:

我正在为网站创建一个简单的通知系统。用户的通知从数据库中提取,如果它们还没有被标记为已看到,然后显示给用户。看不见的以粗体显示。这是我的一些代码:

query = request.db.query(Notification)\
        .filter(Notification.user == request.user)
notifications = query.order_by(Notification.created_at.desc()).all()

print [ notif.seen for notif in notifications ] # [ False, False, False... ]
query.filter(Notification.seen == False).update(
    'seen': True
    )
request.db.commit()
print [ notif.seen for notif in notifications ] # [ True, True, True... ]

您会从我的打印语句中注意到 notifications 在执行 update 查询时被修改,尽管已经使用 .all() 从数据库中提取。

我不想要这种行为。我需要查看notifications ,而不是,以便将以前未见过的字段加粗。

查看文档,我认为将 synchronize_session 参数设置为 False 可能会起作用。

query.filter(Notification.seen == False).update(
    'seen': True
    , False)

但不幸的是,它没有。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

synchronize_session=False 就像你正在做的那样,但你也需要在查看通知之前不提交,或者在你的会话中打开 expire_on_commit=False 。该对象通常在提交后首次访问时从数据库中刷新。

【讨论】:

【参考方案2】:

我认为在这里做任何太棘手的事情(例如中断同步或从会话中删除对象)是不值得的。在这种情况下,最好保存一个事先看不到的通知列表,然后在您的应用程序中使用它。

new_notifications = [notif for notif in notifications if not notif.seen]

# do the update stuff
pass

# later on
for notif in notifications:
    if notif in new_notifications:
        # This one is new, do some stuff
        pass
    else:
        # We already saw this notification, do some other stuff
        pass

如果您需要更好的性能,请将 id 存储在字典中并检查:

new_notifications = dict([(notif.id, None) for notif in notifications if not notif.seen])

if notif.id in new_notifications:
    pass

最后一个解决方案是像这样在通知上设置一个临时属性(可能以更正式的方式使用类方法或其他方式):

for notif in notifications:
    notif.fresh = not notif.seen

那么你的代码依赖于新设置并使用它

【讨论】:

以上是关于停止 SQLAlchemy 更新已从数据库中提取的行的主要内容,如果未能解决你的问题,请参考以下文章

SQLALCHEMY 删除关联对象不会从父子节点中删除

sqlalchemy:停止长时间运行的查询

从现有数据库 SQLAlchemy 获取 DDL

使用 SQLAlchemy ORM 高效更新数据库

使用SQLAlchemy更新对象

如何禁用SQLAlchemy缓存?