Un article assez ancien, mais je viens de passer une heure ou deux à ce sujet, alors je voulais partager ma découverte, d'autant plus que certains des autres commentaires énumérés ne sont pas tout à fait corrects.
TL; DR
Donnez à la table enfant un étranger ou modifiez l'existant, en ajoutant ondelete='CASCADE'
:
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
Et l' une des relations suivantes:
a) Ceci sur la table parent:
children = db.relationship('Child', backref='parent', passive_deletes=True)
b) Ou ceci sur la table enfant:
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Détails
Tout d'abord, malgré ce que dit la réponse acceptée, la relation parent / enfant n'est pas établie en utilisant relationship
, elle est établie en utilisant ForeignKey
. Vous pouvez mettre le relationship
sur les tables parent ou enfant et cela fonctionnera très bien. Bien que, apparemment sur les tables enfants, vous devez utiliser la backref
fonction en plus de l'argument mot-clé.
Option 1 (préférée)
Deuxièmement, SqlAlchemy prend en charge deux types différents de cascade. Le premier, et celui que je recommande, est intégré à votre base de données et prend généralement la forme d'une contrainte sur la déclaration de clé étrangère. Dans PostgreSQL, cela ressemble à ceci:
CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE
Cela signifie que lorsque vous supprimez un enregistrement de parent_table
, toutes les lignes correspondantes dans child_table
seront supprimées pour vous par la base de données. C'est rapide et fiable et probablement votre meilleur pari. Vous configurez cela dans SqlAlchemy ForeignKey
comme ceci (une partie de la définition de la table enfant):
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Le ondelete='CASCADE'
est la partie qui crée le ON DELETE CASCADE
sur la table.
Je t'ai eu!
Il y a une mise en garde importante ici. Remarquez comment j'ai relationship
spécifié avec passive_deletes=True
? Si vous ne l'avez pas, tout ne fonctionnera pas. En effet, par défaut, lorsque vous supprimez un enregistrement parent, SqlAlchemy fait quelque chose de vraiment bizarre. Il définit les clés étrangères de toutes les lignes enfants sur NULL
. Donc, si vous supprimez une ligne d' parent_table
où id
= 5, alors il exécutera essentiellement
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Pourquoi tu voudrais ça, je n'en ai aucune idée. Je serais surpris si de nombreux moteurs de base de données vous permettaient même de définir une clé étrangère valide NULL
, créant ainsi un orphelin. Cela semble être une mauvaise idée, mais il y a peut-être un cas d'utilisation. Quoi qu'il en soit, si vous laissez SqlAlchemy faire cela, vous empêcherez la base de données de pouvoir nettoyer les enfants à l'aide du fichier ON DELETE CASCADE
que vous avez configuré. En effet, il s'appuie sur ces clés étrangères pour savoir quelles lignes enfants supprimer. Une fois que SqlAlchemy les a tous définis sur NULL
, la base de données ne peut pas les supprimer. La définition de passive_deletes=True
empêche SqlAlchemy d'entrer NULL
les clés étrangères.
Vous pouvez en savoir plus sur les suppressions passives dans la documentation SqlAlchemy .
Option 2
L'autre façon dont vous pouvez le faire est de laisser SqlAlchemy le faire pour vous. Ceci est configuré à l'aide de l' cascade
argument du relationship
. Si vous avez la relation définie sur la table parent, cela ressemble à ceci:
children = relationship('Child', cascade='all,delete', backref='parent')
Si la relation concerne l'enfant, procédez comme suit:
parent = relationship('Parent', backref=backref('children', cascade='all,delete'))
Encore une fois, c'est l'enfant, vous devez donc appeler une méthode appelée backref
et y placer les données en cascade.
Avec cela en place, lorsque vous supprimez une ligne parent, SqlAlchemy exécutera en fait des instructions de suppression pour vous permettre de nettoyer les lignes enfants. Ce ne sera probablement pas aussi efficace que de laisser cette base de données gérer si c'est pour vous, donc je ne le recommande pas.
Voici la documentation SqlAlchemy sur les fonctionnalités en cascade qu'il prend en charge.