您在上面看到的代码只是一个示例,但它可以重现此错误:

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,try 存储实例.这会失败,因为_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()之前将not实例添加到会话中.这项工作.但在我的真实(但对于这个问题来说非常复杂)用例中,这并不是一个好的解决方案.

推荐答案

如何关闭autoflush功能:

  • 临时:您可以在查询数据库的代码段上使用no_autoflush上下文管理器,即在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))
    
  • 会话范围:只需将autoflush=False传递给会话制作者:

    return sao.sessionmaker(bind=engine, autoflush=False)()
    

Python-3.x相关问答推荐

如何获得给定列表中所有可能的元素组合?

在多个测试中维护和报告变量

使用递归将int转换为字符串

新行是pandas数据帧中旧行的组合

如何使用魔杖扭曲图像

继承自 Counter 与 dict 的类实例的 Deepcopy

如何使用 Selenium Python 连续单击一个按钮直到另一个元素出现?

从另一个云函数调用带有仅允许内部流量标志的云函数时出现问题

在 string.find() 条件下加入两个 Dataframes

使用 Python 在特定组的列中设置上限

来自嵌套字典的完整地址

为什么 return node.next 会返回整个链表?

无法使用 Python 和 Selenium 检索 href 属性

为什么 setattr 在绑定方法上失败

在 Python 3 中使用 unittest.mock 修补 input()

Pylint 给我最后的新行丢失

Python中的多行日志(log)记录

登录csv文件的正确方法是什么?

为 Python 3 和 PyQt 构建可执行文件

如何在 QGraphicsView 中启用平移和zoom