Sql 炼金术 ush ()并插入 id?

我想这样做:

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.id就是 None。我怎样才能让它工作呢?

120346 次浏览

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

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

  1. 映射的细节
  2. 如果在使用后端时有任何奇怪的地方(例如,SQLite 不为复合主键生成整数值)
  3. 当您打开 echo 时,发出的 SQL 所说的内容

我刚刚遇到了同样的问题,在测试之后我发现这些答案都不足以解决问题。

目前,或者说是 sql伟力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.

就是这么做的。

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

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

我曾经遇到过一个问题,在调用 session.add方法之前将 0分配给 id。数据库正确地分配了 id,但是在 session.flush()之后没有从会话中检索到正确的 id。

谢谢大家。我通过修改列映射解决了我的问题。对我来说,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)

没事!

我的代码是这样的:

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

核心解决方案已经在其他更早的答案中提到过,但是它使用了更新的异步 API。

使用 sql伟力 = = 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

在过去的几个小时/几天/不管怎样,我试图让上述建议工作。最初,我编写的所有插入函数都是这样的:

_add = User(id, user_name, email, ...)

其中圆括号之间的所有项目都是 Nothing 的变量,“ user a”,& quot; a@example.com”,..。

这是我的用户表:

class User(Base):
__tablename__ = "users"
    

id = Column(Integer, primary_key=True, autoincrement=True)
user_name = Column(String(50), unique=True, nullable=False)
email = Column(String(100), unique=True, nullable=False)

SQLAlchemy 正确地处理 _ add 查询,因为它插入具有自动递增 ID 的记录。此外,应该没有为 id 列设置默认值。

我已经用各种方法尝试了上述所有选项(有/没有提交、有/没有刷新、有/没有刷新、一个接一个、语句之间的超时等等)。我甚至改变了整个应用程序/数据库的交互几次。但是在所有情况下,“ _ add.id”要么返回0,要么类似于“ Instance”的内容已被删除,要么其行不存在

刚才我想“ 也许我应该编写一些不同的 _ add 查询,方法是同时定义指定表的列名”是这样的:

_add = User(id=None, user_name=user_name, email=email, etc)

要强调的是,请注意: Id = User _ name = 电邮 = ,在 _ add 查询中。 现在,使用以下按顺序排列的语句,SQLAlchemy 确实返回插入的 ID!

session.add(_add)
print(_add.id)    <-- returns None


session.flush()   <-- does **not** insert record into database, but does increment id,
waiting to be committed. Flush may be omitted, because
session.commit() unconditionally issues session.flush()*
print(_add.id)    <-- returns incremented id


session.commit()  <-- commit is needed to actually insert record into database
print(_add.id)    <-- returns incremented id

虽然已经提供了答案,但是我不清楚 _ add 查询中缺少的列名,因此我的懒惰是问题的原因。 我希望这能帮助某人避免同样的故障排除..。

SQLAlchemy 文档