SQLAlchemy:指定用于模型的会话

SQLAlchemy: Specifying session to use for model

我正在使用 Flask-SQLAlchemy,我需要创建一个没有自动刷新操作的会话。但是,使用 db.session 访问的 Flask-SQLAlchemy 创建的默认作用域会话已打开自动刷新。

我正在对 10 万行进行批量更新,自动刷新导致了严重的性能问题。

我尝试使用以下方法创建一个关闭自动刷新的新会话:

from flask_sqlalchemy import SignallingSession
db_session = SignallingSession(db, autoflush=False)

然后我尝试使用以下方法创建一个新行:

from flask_sqlalchemy import SQLAlchemy, BaseQuery

db = SQLAlchemy(app)

class Tool(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(1024), nullable=True)

add_tool = Tool()
add_tool.title = title

db_session.add(add_tool)

但是,这样做会引发以下异常:

Traceback (most recent call last):
  File "app", line 182, in <module>
called for last item
    import_tools('x.json', 1)
  File "app", line 173, in import_tools
    x.add_to_database()
  File "app", line 126, in add_to_database
    title=metadata['title'], commit=True)
  File "app", line 150, in transfer
    self.db_session.add(import_tool)
  File ".virtualenvs/project/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1492, in add
    self._save_or_update_state(state)
  File ".virtualenvs/project/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1504, in _save_or_update_state
    self._save_or_update_impl(state)
  File ".virtualenvs/project/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1759, in _save_or_update_impl
    self._save_impl(state)
  File ".virtualenvs/project/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1731, in _save_impl
    self._attach(state)
  File ".virtualenvs/project/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1849, in _attach
    state.session_id, self.hash_key))
sqlalchemy.exc.InvalidRequestError: Object '<Tool at 0x11361f4d0>' is already attached to session '1' (this is '2')

我认为发生的事情是,当创建对象时,它附加到 Flask-SQLAlchemy 提供的全局范围会话,而我希望它附加到我创建的会话。我尝试查看 Flask-SQLAlchemy 和 SQLAlchemy 的代码和文档,但找不到问题的根源或解决方案。

有什么方法可以指定在使用模型 class 创建对象时使用哪个会话?还是我遗漏了一些完全不同的东西会导致这个问题?

SQLAlchemy 会话提供 no_autoflush context manager。这将暂停任何刷新,直到您退出该块。

model1 = Model(name='spam')
db.session.add(model1)  # This will flush

with db.session.no_autoflush:
    model2 = Model()
    db.session.add(model2)  # This will not

    model2.name = 'eggs'

db.session.commit()