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

Ran*_*ing 4 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
Run Code Online (Sandbox Code Playgroud)

上面的代码将生成DELETE语句,如下所示:

从blog_tag_map删除WHERE blog_tag_map.blog_id =?AND blog_tag_map.tag_id =?

删除博客WHERE blogs.id =?

有没有办法设置关系,以便没有发布blog_tag_map的DELETE语句?我也试过设置passive_deletes='all'相同的结果.

zzz*_*eek 6

这里,"相关对象" 没有被删除.这将是"标签"."blog_tags_table"不是一个对象,它是一个多对多的表.现在,多对多不支持"passive_deletes ='all'"选项,即包含"secondary"的关系.这将是一个可接受的功能添加,但需要开发和测试工作.

将viewonly = True应用于relationship()可以防止任何更改影响多对多表.如果blog_tags_table是特殊的,那么您希望使用关联对象模式来实现更精细的控制.