SQLAlchemy'on_conflict_do_update'不更新

时间:2018-10-23 10:51:04

标签: python sqlalchemy

我有以下代码想要更新:

In [147]: dff = pd.crosstab(df.Item, df.User)

In [148]: dff = dff.dot(dff.T)

In [149]: np.fill_diagonal(dff.values, 0)

In [150]: dff
Out[150]:
Item  1  2  3
Item
1     0  1  1
2     1  0  0
3     1  0  0

在测试中,我使用def add_electricity_reading( *, period_usage, period_started_at, is_estimated, customer_pk ): from sqlalchemy.dialects.postgresql import insert values = dict( customer_pk=customer_pk, period_usage=period_usage, period_started_at=period_started_at, is_estimated=is_estimated, ) insert_stmt = insert(ElectricityMeterReading).values(**values) do_update_stmt = insert_stmt.on_conflict_do_update( constraint=ElectricityMeterReading.__table_args__[0].name, set_=dict( period_usage=period_usage, period_started_at=period_started_at, is_estimated=is_estimated, ) ) conn = DBSession.connection() conn.execute(do_update_stmt) return DBSession.query(ElectricityMeterReading).filter_by(**dict( period_usage=period_usage, period_started_at=period_started_at, customer_pk=customer_pk, is_estimated=is_estimated, )).one() def test_updates_existing_record_for_started_at_if_already_exists(): started_at = datetime.now(timezone.utc) existing = add_electricity_reading( period_usage=0.102, customer_pk=customer.pk, period_started_at=started_at, is_estimated=True, ) started_at = existing.period_started_at reading = add_electricity_reading( period_usage=0.200, customer_pk=customer.pk, period_started_at=started_at, is_estimated=True, ) # existing record was updated assert reading.period_usage == 0.200 assert reading.id == existing.id 添加现有记录,然后再次执行查询,但更改为period_usage=0.102。当底部的最终查询返回记录时,period_usage仍为0.102。

知道为什么会这样吗?

1 个答案:

答案 0 :(得分:0)

此行为在"What does the Session do?"下的“会话基础”中进行了说明,该会话将引用保存到已加载的对象中,该对象称为identity map结构,因此确保每个主键值仅包含1个唯一对象在会话的生存期内一次存在。您可以在自己的代码中使用以下断言来验证这一点:

assert existing is reading

您正在执行的Core插入(或更新)语句不会使会话与数据库中发生的更改保持同步,例如Query.update()。为了获取新值,您可以expire唯一对象的ORM加载状态:

DBSession.expire(existing)  # or reading, does not matter

# existing record was updated
assert reading.period_usage == 0.200
assert reading.id == existing.id