您在上面看到的代码只是一个示例,但它可以重现此错误:
sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked autoflush;
consider using a session.no_autoflush block if this flush is occurring prematurely)
(sqlite3.IntegrityError) NOT NULL constraint failed: X.nn
[SQL: 'INSERT INTO "X" (nn, val) VALUES (?, ?)'] [parameters: (None, 1)]
映射的实例仍会添加到会话中。实例想知道(这意味着对数据库的查询)是否存在其自身类型的其他实例具有相同的值。还有第二个属性/列(_nn
)。它被指定为NOT NULL
。但默认情况下它是NULL
。
当实例(如样本中)仍然添加到会话中时,对query.one()
的调用会调用自动刷新。此刷新创建INSERT
,尝试存储实例。此操作失败,因为_nn
仍为空,并且违反了NOT NULL
约束。
这就是我目前所理解的。 但问题是为什么它会调用自动刷新?我能阻止吗?
#!/usr/bin/env python3
import os.path
import os
import sqlalchemy as sa
import sqlalchemy.orm as sao
import sqlalchemy.ext.declarative as sad
from sqlalchemy_utils import create_database
_Base = sad.declarative_base()
session = None
class X(_Base):
__tablename__ = 'X'
_oid = sa.Column('oid', sa.Integer, primary_key=True)
_nn = sa.Column('nn', sa.Integer, nullable=False) # NOT NULL!
_val = sa.Column('val', sa.Integer)
def __init__(self, val):
self._val = val
def test(self, session):
q = session.query(X).filter(X._val == self._val)
x = q.one()
print('x={}'.format(x))
dbfile = 'x.db'
def _create_database():
if os.path.exists(dbfile):
os.remove(dbfile)
engine = sa.create_engine('sqlite:///{}'.format(dbfile), echo=True)
create_database(engine.url)
_Base.metadata.create_all(engine)
return sao.sessionmaker(bind=engine)()
if __name__ == '__main__':
session = _create_database()
for val in range(3):
x = X(val)
x._nn = 0
session.add(x)
session.commit()
x = X(1)
session.add(x)
x.test(session)
当然,解决方案是不在调用query.one()
之前将实例添加到会话中。这项工作。但在我的真实情况下(但对于这个问题的复杂性),用例并不是一个很好的解决方案。
答案 0 :(得分:27)
如何关闭autoflush功能:
临时:您可以在查询数据库的代码段上使用no_autoflush上下文管理器,即.handsontable.listbox tr td.current,
.handsontable.listbox tr:hover td {
background: #eee;
}
方法:
X.test
会话范围:只需将def test(self, session):
with session.no_autoflush:
q = session.query(X).filter(X._val == self._val)
x = q.one()
print('x={}'.format(x))
传递给您的sessionmaker:
autoflush=False
答案 1 :(得分:1)
我知道这是旧的,但它可能对使用flask-sqlalchemy时遇到此错误的其他人有所帮助。下面的代码解决了我的自动刷新问题。
db = SQLAlchemy(session_options={"autoflush": False})