Cascadas en SQLAlchemy: delete-orphan y ON DELETE resuelve un problema frecuente en proyectos Python: Expresa quién posee el ciclo de vida de objetos relacionados y qué capa elimina. Esta guía explica el mecanismo, presenta un ejemplo ejecutable y marca los límites que evitan una implementación frágil.
Concepto y caso de uso
La cascada ORM propaga operaciones de Session; ON DELETE pertenece a la foreign key de la base. Son capas distintas que deben coincidir.
Para repasar los fundamentos relacionados, consulta también la guía de relaciones SQLAlchemy. La integración es más simple cuando cada función recibe dependencias y datos explícitamente en lugar de depender de estado global.
Ejemplo práctico
class Order(Base):
items: Mapped[list["Item"]] = relationship(
back_populates="order",
cascade="all, delete-orphan",
passive_deletes=True,
)
class Item(Base):
order_id: Mapped[int] = mapped_column(
ForeignKey("orders.id", ondelete="CASCADE")
)
Usa delete-orphan solo si el hijo no puede existir sin un único padre. passive_deletes permite confiar en la base para colecciones no cargadas.
Decisiones importantes
La elección correcta depende del contrato público, del volumen y del comportamiento ante fallos.
Considera concurrencia, entradas vacías y fallos parciales. Documenta cada límite que afecte a consumidores y usa nombres que expresen intención.
Errores frecuentes
El ejemplo mínimo no sustituye límites, manejo de errores y observabilidad. Configurar delete en ambos lados de muchos-a-muchos puede recorrer y borrar todo el grafo. Bulk delete omite cascadas ORM por instancia.
Evita capturar excepciones sin contexto o devolver resultados parciales como si fueran completos. Un fallo explícito suele ser más seguro que datos silenciosamente incorrectos.
Cómo validar
Valida el comportamiento y no solo el camino feliz. Prueba borrar el padre, desasociar un hijo y hacer eliminación masiva, comprobando siempre las filas restantes.