151

我想做这样的事情:

f = Foo(bar='x')
session.add(f)
session.flush()

# do additional queries using f.id before commit()
print f.id # should be not None

session.commit()

但是f.idNone我尝试它时。我怎样才能让它工作?

4

8 回答 8

161

我刚刚遇到了同样的问题,经过测试,我发现这些答案都不够。

目前,或者从 sqlalchemy .6+ 开始,有一个非常简单的解决方案(我不知道这是否存在于以前的版本中,尽管我想它确实存在):

session.refresh()

因此,您的代码将如下所示:

f = Foo(bar=x)
session.add(f)
session.flush()
# At this point, the object f has been pushed to the DB, 
# and has been automatically assigned a unique primary key id

f.id
# is None

session.refresh(f)
# refresh updates given object in the session with its state in the DB
# (and can also only refresh certain attributes - search for documentation)

f.id
# is the automatically assigned primary key ID given in the database.

这就是如何做到这一点。

于 2011-02-22T20:21:13.610 回答
91

您的示例代码应该可以正常工作。SQLAlchemy 应该为 提供一个值f.id,假设它是一个自动生成的主键列。主键属性在生成时立即在flush()流程中填充,不需要调用commit()。所以这里的答案在于以下一项或多项:

  1. 映射的详细信息
  2. 如果使用的后端有任何奇怪的怪癖(例如,SQLite 不会为复合主键生成整数值)
  3. 当您打开 echo 时发出的 SQL 会说什么
于 2009-08-25T01:06:33.710 回答
32

谢谢大家。我通过修改列映射解决了我的问题。对我来说,autoincrement=True是必需的。

起源:

id = Column('ID', Integer, primary_key=True, nullable=False)

修改后:

id = Column('ID', Integer, primary_key=True, autoincrement=True, nullable=True)

然后

session.flush()  
print(f.id)

没关系!

于 2018-05-30T10:09:55.713 回答
7

与 dpb 给出的答案不同,不需要刷新。刷新后,您可以访问 id 字段,sqlalchemy 会自动刷新在后端自动生成的 id

我遇到了这个问题,经过一番调查,我找到了确切的原因,我的模型是用 id 作为整数字段创建的,在我的表单中,id 用 hiddenfield 表示(因为我不想在我的表单中显示 id)。默认情况下,隐藏字段表示为文本。一旦我使用 widget=hiddenInput()) 将表单更改为整数字段,问题就解决了。

于 2014-10-08T15:33:02.023 回答
1

我曾经在调用方法0之前遇到过分配给 id的问题。session.addid 已由数据库正确分配,但在 之后未从会话中检索到正确的 id session.flush()

于 2015-02-25T14:06:22.670 回答
1

其他更老的答案中已经提到了核心解决方案,但这使用了更新的异步 API。

使用 sqlalchemy==1.4(2.0 风格),以下似乎有效:

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine

engine = create_async_engine(
        "postgresql+asyncpg://user:pass@localhost/db",
        echo=False,
    )


# expire_on_commit=False will prevent attributes from being expired
# after commit.
async_session = sessionmaker(
    engine, expire_on_commit=False, class_=AsyncSession,
)
# default kwarg autoflush=True


async with async_session() as session: 
    async with session.begin(): 
        f = Foo(bar='x')
        session.add(f)
        print(f.id)
        # None

        await session.flush()
        print(f.id)
        # not None
    # commits transaction, closes session
于 2021-12-05T00:47:40.437 回答
0

我的代码是这样工作的:

f = Foo(bar="blabla")
session.add(f)
session.flush()
session.refresh(f, attribute_names=[columns name that you want retrieve]
# so now you can access the id inserted, for example
return f.id # id inserted will be returned
于 2021-07-26T17:39:37.863 回答
-6

您应该尝试使用session.save_or_update(f)而不是session.add(f).

于 2009-08-23T00:04:07.847 回答