我可以触摸"一个SQLAlchemy记录触发" onupdate"?

时间:2016-08-29 21:44:28

标签: python sqlalchemy sql-update

这是一个SQLAlchemy类:

class MyGroup(Base):
    __tablename__ = 'my_group'
    group_id = Column(Integer, Sequence('my_seq'), primary_key=True)
    group_name = Column(String(200), nullable=False, index=True)
    date_created = Column(DateTime, default=func.now())
    date_updated = Column(DateTime, default=func.now(), onupdate=func.now())

无论何时添加group_name或(例如)更新group_name,date_updated字段都会更新。太棒了。

但有时有些情况下我想将某个组标记为"更新"即使组记录本身没有改变(例如,如果更新了不同但相关的表中的数据)。

我可以手动完成:

group = session.query(MyGroup).filter(MyGroup.group_name=='Some Group').one()
group.date_updated = datetime.datetime.utcnow()
session.commit()

但我真的宁愿让模型以自己的方式完成它,而不是重新创建一个Python进程来手动更新日期。 (例如,为避免错误,例如模型使用now()而手动功能错误地使用utcnow()

SQLAlchemy是否有办法触及"触摸"一条记录(有点像UNIX touch),它不会改变任何记录的其他值,但会触发onupdate=函数吗?

3 个答案:

答案 0 :(得分:1)

我没有查看源代码,但是从docs看来这只是通过发出SQL UPDATE命令来触发:

  

onupdate - 标量,Python可调用或ClauseElement,表示要在UPDATE语句中应用于列的默认值,如果此更新的SET子句中不存在此列,则会在更新时调用。这是将ColumnDefault用作for_update = True的位置参数的快捷方式。

如果您的关注点是确保您的“触摸”使用与onupdate功能相同的功能,您可以在模型上定义一个方法来执行触摸,并使onupdate参数指向此方法。

我认为这样的事情会起作用:

class MyGroup(Base):
    __tablename__ = 'my_group'
    group_id = Column(Integer, Sequence('my_seq'), primary_key=True)
    group_name = Column(String(200), nullable=False, index=True)
    date_created = Column(DateTime, default=func.now())
    date_updated = Column(
        DateTime,     
        default=self.get_todays_date,
        onupdate=self.get_todays_date)

    def get_todays_date(self):
        return datetime.datetime.utcnow()

    def update_date_updated(self):
        self.date_updated = self.get_todays_date()

然后您可以像这样更新您的记录:

group.update_date_updated()
session.commit()

答案 1 :(得分:1)

documentation仅需添加以下内容即可:

  

Column.default和Column.onupdate关键字参数也接受Python函数。如果没有为该列提供其他任何值,则在插入或更新时将调用这些函数,并将返回的值用作该列的值。

关键部分:,如果没有为该列提供其他值,则在插入或更新时调用。 关键部分的关键部分:如果没有为该列提供其他值

因此,使用带有空值的简单更新语句,就可以做到:

from sqlalchemy import update    
stmt = update(ModelName).where(ModelName.column.in_(column_values)).values()
db.engine.execute(update_product_mapping_info)

我正在为此documentation使用sqlalchemy.sql.expression.update

这是我的“模型”列定义:

from datetime import datetime
last_updated = Column(db.DateTime, onupdate=datetime.utcnow)

答案 2 :(得分:1)

为了显示一个完整的示例,我以@Chayemor的答案为基础:

import sqlalchemy.sql.functions as func
from sqlalchemy import Column, Integer, String, update

from . import database as db


Base = declarative_base()


class Object(Base):
    __tablename__ = "objects"

    id = Column(Integer, primary_key=True, nullable=False)
    last_update = Column(
        DateTime, 
        server_default=func.now(), 
        onupdate=func.current_timestamp()
    )

    def touch(self):
        stmt = update(Game).where(Game.id == self.id)
        db.engine.execute(stmt)

从此处开始,运行obj.touch()将更新其在数据库中的last_update字段,而无需更改任何其他数据。