SQLAlchemy中具有多对多关系的被动删除不会阻止为相关对象发出DELETE

时间:2014-05-15 04:22:22

标签: sqlalchemy

我试图让SQLAlchemy让我的数据库的外键"删除级联"在两个对象之间的关联表上进行清理。我已经根据文档设置了cascadepassive_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'设置为相同的结果。

1 个答案:

答案 0 :(得分:6)

此处,“相关对象”被删除。这将是“标签”。 blog_tags_table不是一个对象,它是一个多对多表。目前,多对多不支持passive_deletes='all'选项,即包含“辅助”的关系。这将是一个可接受的功能添加,但需要开发和测试工作。

viewonly=True应用于relationship()可防止任何更改影响多对多表。如果blog_tags_table是特殊的,那么你想要使用关联对象模式来进行更精细的控制。

相关问题