Ziemlich alter Beitrag, aber ich habe nur ein oder zwei Stunden damit verbracht, deshalb wollte ich meine Ergebnisse teilen, zumal einige der anderen aufgeführten Kommentare nicht ganz richtig sind.
TL; DR
Geben Sie der untergeordneten Tabelle eine Fremdtabelle oder ändern Sie die vorhandene und fügen Sie Folgendes hinzu ondelete='CASCADE'
:
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
Und eine der folgenden Beziehungen:
a) Dies in der übergeordneten Tabelle:
children = db.relationship('Child', backref='parent', passive_deletes=True)
b) Oder dies auf dem Kindertisch:
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Einzelheiten
Zunächst einmal wird die Eltern-Kind-Beziehung trotz der akzeptierten Antwort nicht durch Verwendung hergestellt relationship
, sondern durch Verwendung ForeignKey
. Sie können die relationship
entweder auf die übergeordnete oder die untergeordnete Tabelle setzen und es wird gut funktionieren. Obwohl Sie anscheinend in den untergeordneten Tabellen die backref
Funktion zusätzlich zum Schlüsselwortargument verwenden müssen.
Option 1 (bevorzugt)
Zweitens unterstützt SqlAlchemy zwei verschiedene Arten der Kaskadierung. Die erste und die von mir empfohlene ist in Ihre Datenbank integriert und hat normalerweise die Form einer Einschränkung für die Fremdschlüsseldeklaration. In PostgreSQL sieht es so aus:
CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE
Dies bedeutet, dass beim Löschen eines Datensatzes parent_table
alle entsprechenden Zeilen in child_table
von der Datenbank für Sie gelöscht werden. Es ist schnell und zuverlässig und wahrscheinlich die beste Wahl. Sie richten dies in SqlAlchemy folgendermaßen ein ForeignKey
(Teil der Definition der untergeordneten Tabelle):
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Das ondelete='CASCADE'
ist der Teil, der das ON DELETE CASCADE
auf dem Tisch erstellt.
Erwischt!
Hier gibt es eine wichtige Einschränkung. Beachten Sie, wie ich eine mit relationship
angegeben habe passive_deletes=True
? Wenn Sie das nicht haben, wird das Ganze nicht funktionieren. Dies liegt daran, dass SqlAlchemy beim Löschen eines übergeordneten Datensatzes standardmäßig etwas wirklich Seltsames tut. Es setzt die Fremdschlüssel aller untergeordneten Zeilen auf NULL
. Wenn Sie also eine Zeile aus parent_table
where id
= 5 löschen , wird sie grundsätzlich ausgeführt
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Warum du das willst, weiß ich nicht. Es würde mich wundern, wenn Sie in vielen Datenbankmodulen sogar einen gültigen Fremdschlüssel festlegen könnten NULL
, um eine Waise zu erstellen. Scheint eine schlechte Idee zu sein, aber vielleicht gibt es einen Anwendungsfall. Wenn Sie dies von SqlAlchemy ausführen lassen, verhindern Sie auf jeden Fall, dass die Datenbank die untergeordneten Elemente mit dem von ON DELETE CASCADE
Ihnen eingerichteten bereinigen kann. Dies liegt daran, dass diese Fremdschlüssel erforderlich sind, um zu wissen, welche untergeordneten Zeilen gelöscht werden sollen. Sobald SqlAlchemy sie alle festgelegt hat, NULL
kann die Datenbank sie nicht mehr löschen. Durch Einstellen von wird passive_deletes=True
verhindert, dass SqlAlchemy NULL
die Fremdschlüssel herausgibt .
Weitere Informationen zu passiven Löschvorgängen finden Sie in den SqlAlchemy-Dokumenten .
Option 2
Die andere Möglichkeit besteht darin, SqlAlchemy dies für Sie tun zu lassen. Dies wird mit dem cascade
Argument von eingerichtet relationship
. Wenn Sie die Beziehung in der übergeordneten Tabelle definiert haben, sieht sie folgendermaßen aus:
children = relationship('Child', cascade='all,delete', backref='parent')
Wenn die Beziehung auf dem Kind liegt, machen Sie es so:
parent = relationship('Parent', backref=backref('children', cascade='all,delete'))
Auch dies ist das untergeordnete Element. Sie müssen also eine aufgerufene Methode aufrufen backref
und die Kaskadendaten dort ablegen.
Wenn Sie eine übergeordnete Zeile löschen, führt SqlAlchemy tatsächlich Löschanweisungen aus, damit Sie die untergeordneten Zeilen bereinigen können. Dies ist wahrscheinlich nicht so effizient wie das Handhaben dieser Datenbank, wenn ich es für Sie nicht empfehle.
Hier sind die SqlAlchemy-Dokumente zu den unterstützten Kaskadenfunktionen .