Досить старий пост, але я просто витратив на це годину-дві, тому я хотів поділитися своїм висновком, тим більше, що деякі з інших перерахованих коментарів не зовсім правильні.
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_tableзвідки id= 5, він в основному буде виконуватися
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Чому ви цього хочете, я поняття не маю. Я був би здивований, якби багато двигунів баз даних навіть дозволили вам встановити дійсний закордонний ключ NULL, створивши сироту. Здається, це погана ідея, але, можливо, є корисний випадок. У будь-якому випадку, якщо ви дозволите цьому зробити SqlAlchemy, ви не зможете базі даних прибирати дітей, використовуючи те, ON DELETE CASCADEщо ви налаштували. Це тому, що він покладається на ті зовнішні ключі, щоб знати, які дочірні рядки видалити. Після того, як SqlAlchemy встановив їх усі NULL, база даних не може їх видалити. Встановлення passive_deletes=Trueперешкод SqlAlchemy відNULL сторонні ключі.
Докладніше про пасивні видалення можна прочитати в документах 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 про каскадні функції, які він підтримує.