【问题标题】:How to delete records from many-to-many (secondary) table in SQLAlchemy?如何从 SQLAlchemy 中的多对多(辅助)表中删除记录?
【发布时间】:2026-01-22 13:55:02
【问题描述】:

我在从包含PostTag 列的PostTag 表中删除记录时遇到问题。这是我的关系表:

tags = db.Table('PostTag',
    db.Column('Tag', db.Integer, db.ForeignKey('Tag.Id')),
    db.Column('Post', db.Integer, db.ForeignKey('Post.Id'))
)

tags = db.relationship(Tag, secondary=tags, backref=db.backref('Post', lazy='dynamic'))

当我这样做时:

from models.Post import Post

posts = Post.query.join(Post.tags).filter(Post.Id == id).all()
if(posts):
   return posts
return False

然后

for posttag in post[0].tags:
    db.session.delete(posttag)
    db.session.flush()

多对多关系中的行被删除,Tag 表中的记录也被删除。

我只需要从PostTag 表中删除某些条件下的记录(例如Post=1

我搜索了互联网,但没有找到任何结论。我不需要多对多关系的级联。

这是sql日志:

 297 Query  DELETE FROM `PostTag` WHERE `PostTag`.`Tag` = 14 AND `PostTag`.`Post` = 3
 297 Query  DELETE FROM `PostTag` WHERE `PostTag`.`Tag` = 14 AND `PostTag`.`Post` = 18
 297 Query  DELETE FROM `Tag` WHERE `Tag`.`Id` = 14

最后一行 297 Query DELETE FROMTagWHERETag.Id= 14 不应该在那里。

更新/也许是解决方案

我通过以下方式解决了这个问题:

sql = 'DELETE FROM PostTag WHERE Post=%s'
db.engine.execute(sql, post, ())

但这不仅仅是 ORM 方式。插入也是如此。我将尝试以这种解决 ORM 的方式。如果我让这个问题消失,我会发布答案。

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    尝试从集合中移除对象:

    post[0].tags.clear()
    

    您还可以删除单个项目:

    post[0].tags.remove(posttag)
    

    【讨论】:

    • "post[0].tags.clear()" - 这对我不起作用。我得到以下信息: AttributeError: 'InstrumentedList' 对象没有属性 'clear'
    • 我在 SQLAlchemy 文档中找不到任何 clear() 函数。能否提供文档链接?
    • 谢谢,clear() 为我解决了类似的问题。
    【解决方案2】:

    试试这个:

    post = db.session.query(Post).get(1)
    post.tags = []
    db.session.commit()
    

    在这里,我们将集合 post.tags 重新定义为空数组并提交更改。为了解释这一点,我将参考SQLAlchemy docs

    SQLAlchemy 中的集合是透明检测的。插装意味着对集合的正常操作进行跟踪,并导致在刷新时将更改写入数据库。

    所以 SQLAlchemy 会跟踪我们对集合 post.tags 所做的更改,并在提交时对其进行更新。

    如果我们只有一个标签(比如sometag),我们可以像这样使用remove 方法:

    post = db.session.query(Post).get(1)
    post.tags.remove(sometag)
    db.session.commit()
    

    【讨论】:

    • 您能解释一下为什么这不起作用吗? tags = post.tags tags = []
    • 它会将其更新为提交,但如果您查看 db 上发生的情况。在我的情况下,它实际上发送了 4000 个删除。虽然它可以发送一个。