删除多对多中间表中的行
我有两个表,它们之间有多对多的关系。有时候我需要刷新数据库,所以我会从这两个表中删除一些数据。但是,已经删除的行之间的关系仍然保存在自动创建的中间表里。
为了更清楚地说明这个问题,这里有一段小代码:
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"这个表也能被清空。
有没有办法做到这一点,而不使用ON DELETE语句,因为SQLite并不总是支持这些语句?
我相信使用Elixir进行多对多关系的人不止我一个,所以这个问题的解决方案可能很简单。
上面的代码会产生sqlalchemy的警告:
sqlalchemy/orm/properties.py:842: SAWarning: 在B.alist上,delete-orphan 级联在多对多或多对一 关系中不被支持,除非设置了single_parent。请在 relationship()中设置single_parent=True。
self._determine_direction()
这只是因为我现在随意尝试在这个多对多关系中添加级联选项。这应该是一个信号,说明delete-orphan并不是正确的选项。
1 个回答
1
我想我找到了答案。首先,这个问题在单独使用sqlalchemy的时候也是一样的。
然后,这种情况似乎只会在使用以下语法时发生:
session.query(B).delete()
不过,可以通过使用以下方式来实现想要的效果:
session.delete(b) #where b is an instance of B
对每个 b 使用 session.delete(b)
进行简单的迭代,可能就能解决问题。
也许有人可以对此 session.query().delete()
和 session.delete()
之间的区别进行评论……