我有两个通过外键相关的表,这里他们使用声明映射
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,但找不到方法。我不知道是否有可能。
答案 0 :(得分:18)
您可以使用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时,它将适用于批量更新,甚至适用于应用程序之外的更新。但也有缺点:
下面的可靠性较低(仅在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。您必须再添加一个触发器或事件处理程序,以支持两个方向的更改传播。