Skip to main content
 首页 » 编程设计

python之删除 ManyToMany 中间表中的行

2025年05月04日9cloudgamer

我有两个表,它们之间存在多对多关系。有时我需要刷新 数据库,所以我从两个表中删除元素。然而,删除行之间的关系仍然存储在自动创建的中间表中。

为了澄清问题,这里有一段小代码:

from elixir import * 
 
metadata.bind = "sqlite:///test.db" 
metadata.bind.echo = True 
 
options_defaults['shortnames'] = True 
 
class A(Entity): 
    name = Field(Unicode(128)) 
    blist = ManyToMany("B",cascade='all,delete, delete-orphan') 
 
class B(Entity): 
    name = Field(Unicode(128)) 
    alist = ManyToMany("A",cascade='all,delete, delete-orphan')  
 
setup_all() 
create_all() 
 
 
a1 = A() 
a1.name = u"john" 
 
b1 = B() 
b1.name = u"blue" 
 
a1.blist.append(b1) 
 
session.commit() 
 
session.query(A).delete() 
session.query(B).delete() 
 
session.commit() 

sqlite 数据库的转储现在包含:

sqlite> .dump 
PRAGMA foreign_keys=OFF; 
BEGIN TRANSACTION; 
CREATE TABLE a ( 
    id INTEGER NOT NULL,  
    name VARCHAR(128),  
    PRIMARY KEY (id) 
); 
CREATE TABLE b ( 
    id INTEGER NOT NULL,  
    name VARCHAR(128),  
    PRIMARY KEY (id) 
); 
CREATE TABLE b_alist__a_blist ( 
    a_id INTEGER NOT NULL,  
    b_id INTEGER NOT NULL,  
    PRIMARY KEY (a_id, b_id),  
    CONSTRAINT a_blist_fk FOREIGN KEY(a_id) REFERENCES a (id),  
    CONSTRAINT b_alist_fk FOREIGN KEY(b_id) REFERENCES b (id) 
); 
INSERT INTO "b_alist__a_blist" VALUES(1,1); 
COMMIT; 

我希望在删除 a1 或 b1 时清空“b_alist__a_blist”表。

如果不使用 SQLite 并不总是支持的 ON DELETE 语句,这是否可能?

因为我肯定不是唯一一个使用 Elixir 的多对多关系的人,所以这个问题的解决方案可能很简单。

上面给出的代码生成 sqlalchemy 警告:

sqlalchemy/orm/properties.py:842: SAWarning: On B.alist, delete-orphan cascade is not supported on a many-to-many or many-to-one relationship when single_parent is not set. Set single_parent=True on the relationship().
self._determine_direction()

这只是因为我现在随机尝试在此 ManyToMany 关系中添加级联选项。这应该表明 delete-orphan 不是正确的选项。

请您参考如下方法:

我想我找到了答案。 首先,单独使用 sqlalchemy 的问题是一样的。

那么,这似乎只有在使用这种语法时才会发生:

session.query(B).delete() 

但是可以通过以下方式获得所需的行为:

session.delete(b)  #where b is an instance of B 

session.delete(b) 对每个 b 的简单迭代可能会达到目的。

也许有人可以评论一下 session.query().delete() 和 session.delete() 的区别...