我想要做这样的事情:
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
。怎样才能让它工作?
我想要做这样的事情:
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
。怎样才能让它工作?
我刚刚遇到了同样的问题,在测试后发现这些答案都不够好。目前,或者说从 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.
那就是如何做到的。
sessionmaker(autoflush=True)
这个组合,加上refresh()函数让我得到了行ID。#grrr - Marcflush()
和commit()
之间的区别,这里有一个很好的解释:https://dev59.com/zm855IYBdhLWcg3wrGdY#4202016。 - Epocflush()
,建议使用commit()
,并紧接着使用session.refresh(f)
来更新。这对我有效,并且我使用的是SQLAlchemy版本 0.6.7
。 - Ricky Levisession.refresh(f)
。 - Nelson G.您的示例代码应该可以直接运行。假设f.id
是自动生成的主键列,那么SQLAlchemy应该已经为其提供了一个值。在生成主键属性时,它们会立即在flush()
过程中填充,并且不需要调用commit()
。因此,答案可能涉及以下一个或多个方面:
谢谢大家。我通过修改列映射解决了我的问题。对我来说,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)
没问题!
_add = User(id, user_name, email, ...)
在圆括号中的所有项都是变量,可以是 None、"user a"、"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,要么返回“实例''已被删除或其行不存在”。
刚才我想:“也许我应该稍微改变我的_add查询方式,通过为指定表定义列名来定义它”,如下所示:
_add = User(id=None, user_name=user_name, email=email, etc)
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
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
await
调用session.flush
,那么ID将不会存在(因为刷新操作还没有发生)。 - undefined我的代码是这样工作的:
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
我曾经遇到过一个问题,就是在调用 session.add
方法之前将 0
赋值给了 id。尽管数据库正确地分配了 id,但在 session.flush()
后未能从会话中检索到正确的 id。
users: list[User] = [User(user_name=..., email=..., etc) for foo in bar]
session.bulk_save_objects(references, return_defaults=True)
assert users[0].id is not None # User.id is now populated.
session.save_or_update(f)
而不是 session.add(f)
。
echo=True
初始化 SA 引擎,并查看在 flush 时执行的 SQL 吗?你所描述的 应该 能够工作并给出 id,但可能存在其他问题导致 f.id 为 None。 - Pavel Repin