'SQLAlchemy: delete rows from associate table from many-to-many relationship
I noticed that when deleting one entry, the corresponding rows from the secondary table are not deleted. here my models:
cashflows_tags_table = Table(
"cashflows_tags",
Base.metadata,
Column("cashflow_id", ForeignKey("cashflows.id"),primary_key=True),
Column("tag_id", ForeignKey("tags.id"), primary_key=True),
)
class Tag(Base):
__tablename__ = "tags"
id = Column(Integer, primary_key=True)
tag = Column(String, nullable=False, unique=True)
class Cashflow(Base):
__tablename__ = "cashflows"
id = Column(Integer, primary_key=True)
date = Column(DateTime, nullable=False)
amount = Column(Float, nullable=False)
description = Column(String, nullable=False)
### Many to Many ###
tags = relationship("Tag", secondary=cashflows_tags_table)
#######
What I understand from the documentation (https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html#deleting-rows-from-the-many-to-many-table) is that the deletion should be propagated automatically. Additional cascade/delete/delete-orphan would cause the deletion of the elements on the other "many" side, which is not what I want.
I am using sqlite, and the following ORM syntax for the deletion:
with Session(db_engine) as session:
ddd = delete(Cashflow).where(Cashflow.id.in_(id_list))
session.execute(ddd)
session.commit()
EDIT
in the end I solved it manually selecting the entry and emptying the tag collection before the deletion (as suggested in other threads). I will still leave the question open, since it is not clear to me if this is the expected behaviour
Solution 1:[1]
If you don't want to set a cascade, session.delete will remove both the CashFlow
and the associated many-to-many records.
cfs = s.scalars(sa.select(Cashflow).where(Cashflow.id.in_(id_list)))
for cs in cfs:
session.delete(cf)
It will emit a DELETE
statement for the many-to-many records first, then the CashFlow
s.
Alternatively, you can enable foreign keys in SQLite and set "CASCADE" as the ondelete behaviour for the foreign key in the association table - only rows associated with the CashFlow to be deleted will be deleted when using sqlachemy.delete.
from sqlalchemy.engine import Engine
# Enable foreign keys (from the SQLAlchemy docs)
@sa.event.listens_for(Engine, 'connect')
def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute('PRAGMA foreign_keys=ON')
cursor.close()
cashflows_tags_table = sa.Table(
'cashflows_tags',
Base.metadata,
sa.Column('cashflow_id', sa.ForeignKey('cashflows.id', ondelete='CASCADE'), primary_key=True),
sa.Column('tag_id', sa.ForeignKey('tags.id'), primary_key=True),
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | snakecharmerb |