sqlalchemy onupdate Query.update()的行为不一致

时间:2018-12-22 10:21:41

标签: python postgresql sqlalchemy flask-sqlalchemy

我正在用Flask实现一个宁静的POST API,使用sqlalchemy更新PostgreSQL中的资源,例如MyResource:

class MyResource(db.Model):
    __tablename__ = 'my_resource'

    res_id = Column(Integer, primary_key=True)
    <other columns>
    time_updated = Column(TIMESTAMP(timezone=True), onupdate=datetime.now(timezone.utc))

有一个MyResource实例是从API的请求有效载荷派生的,我们将其称为input_instance。下面是我更新资源的方法:

input_instance_dict = input_instance.__dict__
input_instance_dict.pop('_sa_instance_state', None)  # this extra meta field will cause error in update().
update_count = MyResource.query.filter(MyResource.res_id == input_instance.res_id).update(input_instance_dict)
db.session.commit()

通过上述操作,除time_updated以外的各列将更新,该列保持为空;我希望它会随着当前日期时间更新。

如果在调用Query.update()之前从输入中删除了time_updated字段,

input_instance_dict.pop('time_updated', None)

然后time_updated列中的空值将被更新为当前日期时间,但是...在随后的更新中,此列的值将保持相同的旧值。

我的疑问是,即使从输入字典中删除了time_updated字段,onupdate也仅对第一次更新有效,而对之后的更新无效。为什么?谢谢。

--- GMT + 8更新12/23 10:56 am

其他观察,我只是重新触发了与昨晚两次相同的更新,time_updated列正在为第一次重试而更新,而没有为第二次重试。这意味着,在第一次更新后,onupdate会在以后的更新中开启和关闭。我无法弄清楚这种模式,什么时候可以用,什么时候不可以用。

1 个答案:

答案 0 :(得分:0)

对于另一个要填充default的时间戳字段,也观察到类似的问题,例如……昨天插入了一条记录,但是今天插入的所有记录最终都具有与time_created相同的值昨天的值。

time_created = Column(TIMESTAMP(timezone=True), nullable=False, default=datetime.now(timezone.utc))

在更改参数(针对defaultonupdate)之后,将Python datetime函数替换为sqlalchemy.func.now()可以解决怪异的行为。

time_created = Column(TIMESTAMP(timezone=True), nullable=False, default=func.now())
time_updated = Column(TIMESTAMP(timezone=True), onupdate=func.now())

我不确定为什么行为会有所不同,有许多教程使用datetime函数作为参数,我想知道这些程序是否存在相同的问题。