Довольно старый пост, но я потратил на это час или два, поэтому я хотел поделиться своим выводом, тем более что некоторые из других перечисленных комментариев не совсем правильные.
TL; DR
Дайте дочерней таблице чужую или измените существующую, добавив ondelete='CASCADE':
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
И одно из следующих отношений:
а) Это в родительской таблице:
children = db.relationship('Child', backref='parent', passive_deletes=True)
б) Или это в дочерней таблице:
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
подробности
Во-первых, несмотря на то, что говорится в принятом ответе, отношения родитель / потомок не устанавливаются с помощью relationship, они устанавливаются с помощью ForeignKey. Вы можете поместить его relationshipв родительскую или дочернюю таблицы, и он будет работать нормально. Хотя, очевидно, в дочерних таблицах вы должны использовать backrefфункцию в дополнение к аргументу ключевого слова.
Вариант 1 (желательно)
Во-вторых, SqlAlchemy поддерживает два разных типа каскадирования. Первый и тот, который я рекомендую, встроен в вашу базу данных и обычно принимает форму ограничения на объявление внешнего ключа. В PostgreSQL это выглядит так:
CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE
Это означает, что при удалении записи из базы данных parent_tableвсе соответствующие строки child_tableбудут удалены за вас. Это быстро и надежно и, вероятно, ваш лучший выбор. Вы устанавливаете это в SqlAlchemy ForeignKeyследующим образом (часть определения дочерней таблицы):
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Это ondelete='CASCADE'та часть, которая создает ON DELETE CASCADEна столе.
Попался!
Здесь есть важная оговорка. Обратите внимание, как я relationshipуказал passive_deletes=True? Если у вас этого нет, все не будет работать. Это связано с тем, что по умолчанию при удалении родительской записи SqlAlchemy делает что-то действительно странное. Он устанавливает для внешних ключей всех дочерних строк значение NULL. Итак, если вы удалите строку из parent_tablewhere id= 5, она в основном выполнит
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Я понятия не имею, зачем тебе это нужно. Я был бы удивлен, если бы многие движки баз данных даже позволили вам установить действительный внешний ключ NULL, создавая сироту. Вроде плохая идея, но, возможно, есть вариант использования. В любом случае, если вы позволите SqlAlchemy сделать это, вы не позволите базе данных очищать дочерние элементы, используя ON DELETE CASCADEнастроенный вами. Это потому, что он полагается на эти внешние ключи, чтобы знать, какие дочерние строки следует удалить. Как только SqlAlchemy установит их все NULL, база данных не сможет их удалить. Установка passive_deletes=Trueпредотвращает выдачу NULLвнешних ключей SqlAlchemy .
Вы можете узнать больше о пассивных удалениях в документации SqlAlchemy .
Вариант 2
Другой способ сделать это - позволить SqlAlchemy сделать это за вас. Это настраивается с использованием cascadeаргумента relationship. Если у вас есть связь, определенная в родительской таблице, она выглядит так:
children = relationship('Child', cascade='all,delete', backref='parent')
Если отношения на ребенке, вы делаете это так:
parent = relationship('Parent', backref=backref('children', cascade='all,delete'))
Опять же, это дочерний элемент, поэтому вам нужно вызвать вызываемый метод backrefи поместить туда каскадные данные.
При этом, когда вы удаляете родительскую строку, SqlAlchemy фактически запускает операторы удаления, чтобы вы могли очистить дочерние строки. Скорее всего, это будет не так эффективно, как позволить этой базе данных обрабатывать, если для вас, поэтому я не рекомендую это делать.
Вот документы SqlAlchemy о поддерживаемых каскадных функциях.