提交后 Flask-SQLAlchemy 多对多邻接列表更改
Flask-SQLAlchemy many-to-many adjacency list changes after commit
我有一个与自身具有多对多关系的模型:一个操作可以被另一个操作或自身阻止。
operation_to_operation_association_table = db.Table(
"preventing_operations",
db.Column("id", db.Integer, primary_key=True),
db.Column("preventing_operation_id", db.Integer, db.ForeignKey("operation.id")),
db.Column("prevents_operation_id", db.Integer, db.ForeignKey("operation.id")))
class Operation(BaseModel): # BaseModel defines id and creation/update times
name = db.Column(db.String)
bodypart_id = db.Column(db.Integer, db.ForeignKey(BodyPart.id))
bodypart = db.relationship("BodyPart", backref="operations")
prevents = db.relationship("Operation", secondary=operation_to_operation_association_table,
foreign_keys=[operation_to_operation_association_table.c.preventing_operation_id],
backref="prevented_by")
def __eq__(self, other):
return other and self.name == other.name and self.bodypart == other.bodypart
然后在 shell 中,来自一个新的数据库:
In [1]: bp = BodyPart(name="liver")
In [2]: db.session.add(bp)
In [3]: db.session.commit()
In [4]: o1, o2 = Operation(name="viewing", bodypart=bp), Operation(name="removing", bodypart=bp)
In [5]: db.session.add_all([o1, o2])
In [6]: db.session.commit()
In [7]: o1, o2
Out[7]: (Viewing the liver (1), Removing the liver (2))
In [8]: o1.prevents, o2.prevents
Out[8]: ([], [])
In [9]: o2.prevents.append(o1)
In [10]: o1.prevents, o2.prevents
Out[10]: ([], [Viewing the liver (1)])
In [11]: db.session.commit()
In [12]: o1.prevents, o2.prevents
Out[12]: ([Viewing the liver (1)], [])
提交会切换列表?!
记录查询,SQLAlchemy 发送数据库的插入查询好像是错误的:
INSERT INTO preventing_operations (prevents_operation_id) VALUES (?)
with values (1,)
应该是:
INSERT INTO preventing_operations (prevents_operation_id, preventing_operation_id) VALUES (?)
with values (2, 1)
我在这里做错了什么?我是否错误地定义了我的关系?那为什么它只在我提交时才改变?
问题出在 foreign_keys
设置上,我实际上不确定 foreign_keys 到底需要做什么。
但我建议改用primaryjoin
和secondaryjoin
。这样设置对我来说更明显(并且有效):
prevents = relationship(
"Operation",
secondary=operation_to_operation,
primaryjoin=id == operation_to_operation.c.preventing_operation_id,
secondaryjoin=id == operation_to_operation.c.prevents_operation_id,
backref="prevented_by")
这里是the working example and module with base model.
运行 示例如下:
- 下载这两个文件,保存到同一个文件夹中(或克隆 repo)
- 运行`pythonmany_many_save_issue.py。
我用 SQLAlchemy==1.0.6 测试过。
我有一个与自身具有多对多关系的模型:一个操作可以被另一个操作或自身阻止。
operation_to_operation_association_table = db.Table(
"preventing_operations",
db.Column("id", db.Integer, primary_key=True),
db.Column("preventing_operation_id", db.Integer, db.ForeignKey("operation.id")),
db.Column("prevents_operation_id", db.Integer, db.ForeignKey("operation.id")))
class Operation(BaseModel): # BaseModel defines id and creation/update times
name = db.Column(db.String)
bodypart_id = db.Column(db.Integer, db.ForeignKey(BodyPart.id))
bodypart = db.relationship("BodyPart", backref="operations")
prevents = db.relationship("Operation", secondary=operation_to_operation_association_table,
foreign_keys=[operation_to_operation_association_table.c.preventing_operation_id],
backref="prevented_by")
def __eq__(self, other):
return other and self.name == other.name and self.bodypart == other.bodypart
然后在 shell 中,来自一个新的数据库:
In [1]: bp = BodyPart(name="liver")
In [2]: db.session.add(bp)
In [3]: db.session.commit()
In [4]: o1, o2 = Operation(name="viewing", bodypart=bp), Operation(name="removing", bodypart=bp)
In [5]: db.session.add_all([o1, o2])
In [6]: db.session.commit()
In [7]: o1, o2
Out[7]: (Viewing the liver (1), Removing the liver (2))
In [8]: o1.prevents, o2.prevents
Out[8]: ([], [])
In [9]: o2.prevents.append(o1)
In [10]: o1.prevents, o2.prevents
Out[10]: ([], [Viewing the liver (1)])
In [11]: db.session.commit()
In [12]: o1.prevents, o2.prevents
Out[12]: ([Viewing the liver (1)], [])
提交会切换列表?!
记录查询,SQLAlchemy 发送数据库的插入查询好像是错误的:
INSERT INTO preventing_operations (prevents_operation_id) VALUES (?)
with values (1,)
应该是:
INSERT INTO preventing_operations (prevents_operation_id, preventing_operation_id) VALUES (?)
with values (2, 1)
我在这里做错了什么?我是否错误地定义了我的关系?那为什么它只在我提交时才改变?
问题出在 foreign_keys
设置上,我实际上不确定 foreign_keys 到底需要做什么。
但我建议改用primaryjoin
和secondaryjoin
。这样设置对我来说更明显(并且有效):
prevents = relationship(
"Operation",
secondary=operation_to_operation,
primaryjoin=id == operation_to_operation.c.preventing_operation_id,
secondaryjoin=id == operation_to_operation.c.prevents_operation_id,
backref="prevented_by")
这里是the working example and module with base model.
运行 示例如下: - 下载这两个文件,保存到同一个文件夹中(或克隆 repo) - 运行`pythonmany_many_save_issue.py。
我用 SQLAlchemy==1.0.6 测试过。