SQLAlchemy ORM自增id属性赋值疑问:添加实例后id为何为None?
问题描述
我创建了一张仅包含bigserial类型自增主键字段id的user表:
create table user ( id bigserial primary key );
我预期新建的类实例的id属性会有值,但实际为None:
>>> u = User() >>> session.add(u) >>> print(u.id) None
不过执行查询语句后,该属性就有值了:
>>> session.query(User.id).all() >>> print(u.id) 1
为何第一次调用时id字段为空,第二次却有值?
原因解释
这是因为PostgreSQL的bigserial自增主键是数据库端生成的,SQLAlchemy默认不会在session.add()时立即触发数据库的主键生成操作,而是把这个操作延迟到事务提交或者需要与数据库交互的查询执行时才执行。
具体细节:
- 执行
session.add(u)时,SQLAlchemy只是将对象加入会话的待提交队列,并没有向数据库发送INSERT语句,此时数据库还未生成主键值,所以u.id为None。 - 执行
session.query(User.id).all()时,SQLAlchemy会自动触发**会话刷新(flush)**操作:把待提交的INSERT语句发送给数据库,数据库执行后生成自增id,SQLAlchemy再将这个值同步回对象实例u,因此此时u.id会显示正确值。
如果想在add之后立即获取id,可以手动调用session.flush(),无需执行查询就能同步主键值:
>>> u = User() >>> session.add(u) >>> session.flush() >>> print(u.id) 1
内容的提问来源于stack exchange,提问作者ipozdeev-tw
相关产品推荐
相关产品推荐

