我有一个Pyramid / SQLAlchemy,MySQL python应用程序。 当我执行原始SQL INSERT查询时,没有任何内容写入数据库。 但是,在使用ORM时,我可以写入数据库。我阅读了文档,我读到了关于ZopeTransactionExtension的内容,阅读了大量的SO问题,但都无济于事。 到目前为止还没有工作:
transaction.commit()
- 没有任何内容写入数据库。我确实意识到这个陈述对ZopeTransactionExtension来说是必要的,但它不会在这里发挥作用。dbsession().commit
- 由于我使用的是ZopeTransactionExtension,因此无法正常工作dbsession().close()
- 没有写任何内容dbsession().flush()
- 没有写任何内容mark_changed(session)
-
文件" /home/dev/.virtualenvs/sc/local/lib/python2.7/site-packages/zope/sqlalchemy/datamanager.py",第198行,在join_transaction中 如果session.twophase: AttributeError:' scoped_session'对象没有属性'""
engine.execute(...)
我正在寻找如何使用scoped_session
(我的代码中为dbsession()
)执行原始SQL
这是我的SQLAlchemy设置(models/__init__.py
)
def dbsession():
assert (_dbsession is not None)
return _dbsession
def init_engines(settings, _testing_workarounds=False):
import zope.sqlalchemy
extension = zope.sqlalchemy.ZopeTransactionExtension()
global _dbsession
_dbsession = scoped_session(
sessionmaker(
autoflush=True,
expire_on_commit=False,
extension=extension,
)
)
engine = engine_from_config(settings, 'sqlalchemy.')
_dbsession.configure(bind=engine)
这是我写的一个用于隔离问题的python脚本。它类似于问题发生的真实环境。我想要的是让下面的脚本将数据插入到DB中:
# -*- coding: utf-8 -*-
import sys
import transaction
from pyramid.paster import setup_logging, get_appsettings
from sc.models import init_engines, dbsession
from sqlalchemy.sql.expression import text
def __main__():
if len(sys.argv) < 2:
raise RuntimeError()
config_uri = sys.argv[1]
setup_logging(config_uri)
aa = init_engines(get_appsettings(config_uri))
session = dbsession()
session.execute(text("""INSERT INTO
operations (description, generated_description)
VALUES ('hello2', 'world');"""))
print list(session.execute("""SELECT * from operations""").fetchall()) # prints inserted data
transaction.commit()
print list(session.execute("""SELECT * from operations""").fetchall()) # doesn't print inserted data
if __name__ == '__main__':
__main__()
有趣的是,如果我这样做:
session = dbsession()
session.execute(text("""INSERT INTO
operations (description, generated_description)
VALUES ('hello2', 'world');"""))
op = Operation(generated_description='aa', description='oo')
session.add(op)
然后第一个打印输出原始SQL插入行(&#39; hello2&#39;&#39;&#39;&#39;),第二个打印输出两个行,实际上两行都插入到数据库中。
我无法理解为什么使用ORM插入以及原始SQL&#34;修复&#34;它
我真的需要能够在scoped_session上调用execute()以使用原始SQL将数据插入到数据库中。有什么建议吗?
答案 0 :(得分:3)
自从我将原始sql与sqlalchemy混合以来已经有一段时间了,但无论何时混合它们,您都需要了解ORM幕后发生的事情。首先,检查autocommit标志。如果未正确配置zope事务,则ORM插入可能会触发提交。
实际上,在查看zope文档后,似乎手动执行语句需要额外的步骤。来自readme:
默认情况下,zope.sqlalchemy将会话置于“活动”状态。他们是什么时候说的 第一次使用。 ORM写操作会自动将会话移动到 &#39;变更&#39;州。这可以避免不必要的数据库提交。有时它 必须通过SQL直接与数据库交互。它不是 可以猜测这样的操作是读还是写。所以我们 手动SQL语句写入时,必须手动将会话标记为已更改 到DB。
>>> session = Session()
>>> conn = session.connection()
>>> users = Base.metadata.tables['test_users']
>>> conn.execute(users.update(users.c.name=='bob'), name='ben')
<sqlalchemy.engine...ResultProxy object at ...>
>>> from zope.sqlalchemy import mark_changed
>>> mark_changed(session)
>>> transaction.commit()
>>> session = Session()
>>> str(session.query(User).all()[0].name)
'ben'
>>> transaction.abort()
似乎你没有这样做,所以transaction.commit什么也没做。