Una publicación bastante antigua, pero acabo de pasar una hora o dos en esto, así que quería compartir mi hallazgo, especialmente porque algunos de los otros comentarios enumerados no son del todo correctos.
TL; DR
Dele a la tabla secundaria una ajena o modifique la existente, agregando ondelete='CASCADE'
:
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
Y una de las siguientes relaciones:
a) Esto en la mesa principal:
children = db.relationship('Child', backref='parent', passive_deletes=True)
b) O esto en la mesa del niño:
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
Detalles
En primer lugar, a pesar de lo que dice la respuesta aceptada, la relación padre / hijo no se establece mediante el uso de relationship
, se establece mediante el uso ForeignKey
. Puede poner el relationship
en la tabla principal o secundaria y funcionará bien. Aunque, aparentemente en las tablas secundarias, debe usar la backref
función además del argumento de palabra clave.
Opción 1 (preferida)
En segundo lugar, SqlAlchemy admite dos tipos diferentes de conexión en cascada. El primero, y el que recomiendo, está integrado en su base de datos y generalmente toma la forma de una restricción en la declaración de clave externa. En PostgreSQL se ve así:
CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE
Esto significa que cuando elimine un registro de parent_table
, child_table
la base de datos eliminará todas las filas correspondientes . Es rápido y confiable y probablemente su mejor opción. Configuraste esto en SqlAlchemy a través deForeignKey
esta manera (parte de la definición de la tabla secundaria):
parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))
los ondelete='CASCADE'
es la parte que crea el ON DELETE CASCADE
sobre la mesa.
¡Te tengo!
Aquí hay una advertencia importante. ¿Observa cómo he relationship
especificado con passive_deletes=True
? Si no tiene eso, todo no funcionará. Esto se debe a que, de forma predeterminada, cuando elimina un registro principal, SqlAlchemy hace algo realmente extraño. Establece las claves externas de todas las filas secundarias en NULL
. Entonces, si elimina una fila de parent_table
donde id
= 5, básicamente se ejecutará
UPDATE child_table SET parent_id = NULL WHERE parent_id = 5
Por qué querrías esto, no tengo idea. Me sorprendería si muchos motores de bases de datos incluso le permitieran establecer una clave externa válida para NULL
crear un huérfano. Parece una mala idea, pero tal vez haya un caso de uso. De todos modos, si deja que SqlAlchemy haga esto, evitará que la base de datos pueda limpiar a los niños usando el archivo ON DELETE CASCADE
que configuró. Esto se debe a que se basa en esas claves externas para saber qué filas secundarias eliminar. Una vez que SqlAlchemy los ha configurado a todos NULL
, la base de datos no puede eliminarlos. Establecer elpassive_deletes=True
evita que SqlAlchemy extraiga NULL
las claves externas.
Puede leer más sobre eliminaciones pasivas en el documentos de SqlAlchemy .
opcion 2
La otra forma en que puede hacerlo es dejar que SqlAlchemy lo haga por usted. Esto se configura utilizando el cascade
argumento de relationship
. Si tiene la relación definida en la tabla principal, se ve así:
children = relationship('Child', cascade='all,delete', backref='parent')
Si la relación es del niño, hazlo así:
parent = relationship('Parent', backref=backref('children', cascade='all,delete'))
Nuevamente, este es el hijo, por lo que debe llamar a un método llamado backref
y poner los datos en cascada allí.
Con esto en su lugar, cuando elimina una fila principal, SqlAlchemy ejecutará declaraciones de eliminación para que pueda limpiar las filas secundarias. Es probable que esto no sea tan eficiente como dejar que esta base de datos se encargue de usted, así que no lo recomiendo.
Aquí están los documentos de SqlAlchemy sobre las funciones en cascada que admite.