我试图让SQLAlchemy让我的数据库的外键"删除级联"在两个对象之间的关联表上进行清理。我已经根据文档设置了cascade
和passive_delete
关系。但是,当将相关对象加载到主对象的集合中并从主会话中删除主对象时,SQLAlchemy会在辅助表上发出与主要和辅助对象相关的记录的删除语句。
例如:
import logging
import sqlalchemy as sa
import sqlalchemy.ext.declarative as sadec
import sqlalchemy.orm as saorm
engine = sa.create_engine('sqlite:///')
engine.execute('PRAGMA foreign_keys=ON')
logging.basicConfig()
_logger = logging.getLogger('sqlalchemy.engine')
meta = sa.MetaData(bind=engine)
Base = sadec.declarative_base(metadata=meta)
sess = saorm.sessionmaker(bind=engine)
session = sess()
blog_tags_table = sa.Table(
'blog_tag_map',
meta,
sa.Column('blog_id', sa.Integer, sa.ForeignKey('blogs.id', ondelete='cascade')),
sa.Column('tag_id', sa.Integer, sa.ForeignKey('tags.id', ondelete='cascade')),
sa.UniqueConstraint('blog_id', 'tag_id', name='uc_blog_tag_map')
)
class Blog(Base):
__tablename__ = 'blogs'
id = sa.Column(sa.Integer, primary_key=True)
title = sa.Column(sa.String, nullable=False)
tags = saorm.relationship('Tag', secondary=blog_tags_table, passive_deletes=True,
cascade='save-update, merge, refresh-expire, expunge')
class Tag(Base):
__tablename__ = 'tags'
id = sa.Column(sa.Integer, primary_key=True)
label = sa.Column(sa.String, nullable=False)
meta.create_all(bind=engine)
blog = Blog(title='foo')
blog.tags.append(Tag(label='bar'))
session.add(blog)
session.commit()
# sanity check
assert session.query(Blog.id).count() == 1
assert session.query(Tag.id).count() == 1
assert session.query(blog_tags_table).count() == 1
_logger.setLevel(logging.INFO)
session.commit()
# make sure the tag is loaded into the collection
assert blog.tags[0]
session.delete(blog)
session.commit()
_logger.setLevel(logging.WARNING)
# confirm check
assert session.query(Blog.id).count() == 0
assert session.query(Tag.id).count() == 1
assert session.query(blog_tags_table).count() == 0
上面的代码将生成DELETE语句,如下所示:
从blog_tag_map删除WHERE blog_tag_map.blog_id =? AND blog_tag_map.tag_id =?
DELETE FROM blog WHERE blogs.id =?
有没有办法设置关系,以便不会发布blog_tag_map的DELETE语句?我也尝试将passive_deletes='all'
设置为相同的结果。
答案 0 :(得分:6)
此处,“相关对象”不被删除。这将是“标签”。 blog_tags_table
不是一个对象,它是一个多对多表。目前,多对多不支持passive_deletes='all'
选项,即包含“辅助”的关系。这将是一个可接受的功能添加,但需要开发和测试工作。
将viewonly=True
应用于relationship()
可防止任何更改影响多对多表。如果blog_tags_table
是特殊的,那么你想要使用关联对象模式来进行更精细的控制。