【问题标题】:What is this ZopeTransactionEvents error with SQLAlchemy while updating a Pyramid application?更新 Pyramid 应用程序时,SQLAlchemy 的 ZopeTransactionEvents 错误是什么?
【发布时间】:2021-02-05 17:25:35
【问题描述】:

我正在将 Pyramid/SQLAlchemy 遗留代码从一个在 Python 2.7 下运行良好的应用程序更新到 Python 3.8,并在本地运行它。所有必要的要求都安装了 pip 并且 setup.py 运行没有错误。

在使用我的本地 .ini 文件运行 initialise 时,一切顺利,数据库表 (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)

现在进入下一个错误。

【问题讨论】:

  • 什么是transaction.manager?它是在某处进口的吗?
  • 这是 Pyramid/SQLalchemy 方式的一部分:docs.pylonsproject.org/projects/pyramid/en/latest/…
  • 在查看 SQLAlchemy 或 Pyramid 之前,我会检查您自己的代码。自编写代码以来,事务管理器中的实现或接口可能发生了变化。请粘贴您如何定义DBSession。向下滚动一点后,当前的约定在this step of a Pyramid tutorial 中演示。
  • 添加到上面的问题中
  • 那么介意将我的答案标记为正确吗?

标签: python python-3.x sqlalchemy pyramid pylons


【解决方案1】:

这是由于 zope.sqlalchemy v1.2 中引入的一项重大更改。详情见zope.sqlalchemy pypi page

为了让事情更清楚,我们将 ZopeTransactionExtension 类重命名为 ZopeTransactionEvents。使用“注册”版本的现有代码保持兼容。

从 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() 而不使用任何参数)。

【讨论】:

  • 我已经将ZopeTransactionExtension 的实例更改为ZopeTransactionEvents,并将DBSession 更改为DBSession = scoped_session(sessionmaker(extension=ZopeTransactionEvents()))。似乎有两种选择:使用“注册”并恢复为 ZopeTransactionExtension 或更新为 ZopeTransactionEvents 并更改 DBSession - 更具前瞻性?
  • 谢谢,明天我会再仔细阅读一遍 - 并了解ZopeTransactionEvents … after_commit 错误,并尝试使用register 恢复到ZopeTransactionExtension...
  • 嗯。尝试了上面的更新,它产生:DBSession = scoped_session(sessionmaker(**options)) NameError: name 'options' is not defined - 坚持尝试修复 ` 这至少让我回到原来的错误
  • 这是正确的答案。可能还有其他因素在发生。从源代码 (github.com/zopefoundation/zope.sqlalchemy/blob/master/src/zope/…) 中可以看出,需要调用 register,因为它调用 ZopeTransactionExtenstion 并设置事务事件。
猜你喜欢
  • 2011-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
  • 2012-11-29
相关资源
最近更新 更多