这不是一个问题,我只想了解。考虑以下代码:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
class AB(Base):
__tablename__= 'ab'
id_a = Column(Integer, ForeignKey('a.id', ondelete='CASCADE'), primary_key=True)
id_b = Column(Integer, ForeignKey('b.id', ondelete='CASCADE'), primary_key=True)
rel = Column(Unicode)
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
#1: doesn’t work try to set id_b to null
rel_a = relationship('AB')
# Works, but cascade='all' seems uneeded to me
rel_a = relationship('AB', cascade='all')
# Works
rel_a = relationship('AB', passive_deletes=True)
engine = create_engine('sqlite://', echo=True)
import logging
logger = logging.getLogger('sqlalchemy.engine.base.Engine')
logger.setLevel(logging.DEBUG)
handler = logger.handlers[0]
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter('%(levelname)s %(message)s', ''))
Base.metadata.create_all(engine)
sess = sessionmaker(engine)()
a1 = A()
b1 = B()
ab = AB()
sess.add_all([a1,b1])
sess.flush()
ab.id_a = a1.id
ab.id_b = b1.id
ab.rel = u'truite'
sess.add(ab)
sess.flush()
sess.delete(b1)
sess.flush()
我希望在删除AB
的相关记录时删除B
表中的记录。
我尝试了3种类型的关系(检查B表):
1:不起作用(AssertionError:依赖关系规则尝试在实例''上删除主键列'ab.id_b'),而如果尝试直接在数据库中删除它,则约束正确使用,并删除AB中的记录。
2:工作,我不明白为什么需要这样做,因为生成的数据库是相同的(你可以检查输出上的差异)
3:有效,数据库约束可以完成工作。
离开(3),我不明白为什么需要(2),因为ondelete='cascade'
已经设置,生成的DB是相同的。我的猜测是(1),SQLAlchemy有足够的信息来保持正确的行为。
我错过了什么吗?感谢。
答案 0 :(得分:10)
cascade
上的{p> relationship
配置了Session
个操作的级联,例如Session.delete
。它独立于您对数据库本身中的外键约束可能具有的任何ON X CASCADE
指令。
在您的情况下,让cascade='all'
告诉SQLAlchemy将Session.delete
(以及其他操作)从父对象(AB
)级联到子对象。没有它,默认的操作模式是将NULL放入外键列并让引用的对象为。
另一方面,passive_deletes=True
指示SQLAlchemy依赖数据库通过ON DELETE CASCADE
指令清除已删除的对象。这可以防止SQLAlchemy自行发出DELETE
查询,就像在relationship(cascade=...)
情况下一样。