Триггер в sqlachemy
у меня есть две таблицы, связанные через внешний ключ, здесь они используют декларативное отображение
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)
Итак, я хотел бы обновить соответствующие задачи.состояние, когда обс.состояние изменяется на значение 2. В настоящее время я делаю это вручную (используя отношение под названием task)
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. Я читал вставить обновить значения по умолчанию несколько раз, но не могу найти путь. Я даже не знаю, возможно ли это.
1 ответов
Вы можете создать триггер в базе данных класс DDL:
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, когда задача обновляется. Вы должны добавить еще один триггер или обработчик событий для поддержки распространения изменений в обоих направлениях.