更新 Pyramid 应用程序时 SQLAlchemy 的 ZopeTransactionEvents 错误是什么?

What is this ZopeTransactionEvents error with SQLAlchemy while updating a Pyramid application?

我正在将 Pyramid/SQLAlchemy 遗留代码更新为 Python 3.8,该应用程序在 Python 2.7 下运行良好,并且在本地 运行。所有必要的要求都已安装 pip,setup.py 运行无误。

在运行initialise上用我本地的.ini文件,一切顺利,数据库表(MariaDB)都写好了。

在models.py

from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    relationship,
    backref,
    synonym,
    )
from zope.sqlalchemy import ZopeTransactionEvents
#[...]
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionEvents()))

在主应用程序中,在获得最终输入并尝试将其添加到位于 DBSession.add(user):

的数据库后,此函数失败并显示 'ZopeTransactionEvents' object has no attribute 'after_commit'
def do_create_admin_user(self):
    from ..models import User
    from getpass import getpass
    print("Create an administrative user")
    fullname = input("full name: ")
    username = input("username: ")
    if not username:
        self.log.info("missing username - aborted")
        return
    if len(username) > 50:
        self.log.info("username too long - aborted")
        return
    password = getpass("password for {}: ".format(username))

    with transaction.manager:
        user = User(
            username=username,
            fullname=fullname,
            administrator=True,
            password=password
        )
        DBSession.add(user)
    self.log.info("{} created".format(username))

这里是堆栈跟踪的两个关键部分:

Traceback (most recent call last):
"[...]sqlalchemy/util/_collections.py", line 1055, in __call__
    return self.registry.value
AttributeError: '_thread._local' object has no attribute 'value'

During handling of the above exception, another exception occurred:

[废话省略]

"[...]sqlalchemy/orm/deprecated_interfaces.py", line 367, in _adapt_listener
    ls_meth = getattr(listener, meth)
AttributeError: 'ZopeTransactionEvents' object has no attribute 'after_commit'

这个特定问题使进程停止,尽管经过数天的研究(以及一些无用的黑客攻击),我仍未找到解决方案。这是一个遗留项目,我以前不熟悉 Pyramid 或 SQAlchemy,所以在我前进的过程中找到我的路。


固定

最后,这就是有效的方法,即 sessionmaker()

没有参数
from zope.sqlalchemy import register
# ...
DBSession = scoped_session(sessionmaker())
register(DBSession)

现在进入下一个错误。

这是由于 zope.sqlalchemy v1.2 中引入的重大更改。请参阅 zope.sqlalchemy pypi page

中的详细信息

To make things clearer we renamed the ZopeTransactionExtension class to ZopeTransactionEvents. Existing code using the ‘register’ version stays compatible.

从 1.1 升级

你的旧代码是这样的:

from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), **options))

变为:

from zope.sqlalchemy import register

DBSession = scoped_session(sessionmaker(**options))
register(DBSession)

编辑

本质上它是对 1.2 版中引入的 zope.sqlalchemy API 的一个小的破坏性更改,现在是 方式 。您现在不是通过关键字参数注册扩展,而是使用 register 可调用项显式注册会话。

以上内容直接引用自文档。它可能并不明显,但 **options 的使用是指可选的关键字参数。如果你没有使用任何关键字参数,那么这将被省略(即只调用 sessionmaker() 不带参数)。