Cascade on query([model]).delete() not working

Issue #3902 closed
Martin Uhrin created an issue

The final assert here fails because session.query([model]).delete doesn't seem to cascade while deleting the object directly has the expected behaviour.

There is a TODO on line 3044 of query.py so I guess this is a known problem.

from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm import sessionmaker


def create_bob(sess):
    bob = User(id=1)
    bob.addresses.append(Address())
    sess.add(bob)
    sess.commit()
    return bob


Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)


class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)


class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    user = relationship("User", backref=backref("addresses", cascade='all'))


Base.metadata.create_all(engine)
sess = Session()

bob = create_bob(sess)
assert sess.query(User).count() == 1
assert sess.query(Address).count() == 1

sess.delete(bob)
sess.commit()
assert sess.query(User).count() == 0
assert sess.query(Address).count() == 0

bob = create_bob(sess)
assert sess.query(User).count() == 1
assert sess.query(Address).count() == 1

sess.query(User).delete()
sess.commit()
assert sess.query(User).count() == 0
assert sess.query(Address).count() == 0

Comments (6)

  1. Mike Bayer repo owner

    this is a documented limitation of query.delete():

    http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query%20delete#sqlalchemy.orm.query.Query.delete

    The Query.delete() method is a “bulk” operation, which bypasses ORM unit-of-work automation in favor of greater performance. Please read all caveats and warnings below. The method does not offer in-Python cascading of relationships - it is assumed that ON DELETE CASCADE/SET NULL/etc. is configured for any foreign key references which require it, otherwise the database may emit an integrity violation if foreign key references are being enforced.

    you'd need to configure your FOREIGN KEY appropriately for bulk to work.

  2. Mike Bayer repo owner

    the TODO message is from dcad710de2cff2ceeef18dbd06eb4b263b8c39ad and is from 2008, it is long obsolete and will remove. in-Python cascades are not feasible with bulk operations because they would require that the full table contents are loaded into memory for them to be processed, defeating the whole purpose of using query.delete().

  3. Log in to comment