我有两个通过外键关联的表,这里他们使用的是声明式映射
class Task(DeclarativeBase):
__tablename__ = 'task'
id = Column(Integer, primary_key=True)
state = Column(Integer, default=0)
obs_id = Column(Integer, ForeignKey('obs.id'), nullable=False)
class Obs(DeclarativeBase):
__tablename__ = 'obs'
id = Column(Integer, primary_key=True)
state = Column(Integer, default=0)
因此,我想在 obs.state 更改为值 2 时更新相关的 task.state。目前我正在手动执行(使用称为任务的关系)
obs.state = 2
obs.task.state = 2
但我更喜欢使用触发器来完成它。我已经检查过这在 sqlite 中有效
CREATE TRIGGER update_task_state UPDATE OF state ON obs
BEGIN
UPDATE task SET state = 2 WHERE (obs_id = old.id) and (new.state = 2);
END;
但我找不到如何在 sqlalchemy 中表达它。我读过insert update defaults好几次了,还是找不到路。我什至不知道这是否可能。
最佳答案
您可以使用 DDL class 在数据库中创建触发器:
update_task_state = DDL('''\
CREATE TRIGGER update_task_state UPDATE OF state ON obs
BEGIN
UPDATE task SET state = 2 WHERE (obs_id = old.id) and (new.state = 2);
END;''')
event.listen(Obs.__table__, 'after_create', update_task_state)
这是最可靠的方法:当不使用 ORM 时,它适用于批量更新,甚至适用于应用程序外部的更新。但是也有缺点:
- 您必须确保您的触发器存在并且是最新的;
- 它不可移植,所以如果你改变数据库,你必须重写它;
- SQLAlchemy 不会更改已加载对象的新状态,除非您使它过期(例如,使用某些事件处理程序)。
下面是一个不太可靠的(它只在 ORM 级别进行更改时有效),但更简单的解决方案:
from sqlalchemy.orm import validates
class Obs(DeclarativeBase):
__tablename__ = 'obs'
id = Column(Integer, primary_key=True)
state = Column(Integer, default=0)
@validates('state')
def update_state(self, key, value):
self.task.state = value
return value
我的两个例子都以一种方式工作,即它们在 obs 发生变化时更新任务,但在任务更新时不触及 obs。您必须再添加一个触发器或事件处理程序以支持双向更改传播。
关于python - 在 sqlalchemy 中触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7888846/