我有一些模型,它们之间的关系定义如下:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True, nullable=False)
children = Relationship(Child, lazy='joined')
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True, nullable=False)
father_id = Column(Integer, ForeignKey('parent.id'), nullable=False)
如果我在会话中添加一个孩子(使用session.add(Child(...))
),我会期望其父亲的孩子关系在刷新会话后更新以包括这个孩子。但是,我没有看到。
parent = session.query(Parent).get(parent_id)
num_children = len(parent.children)
# num_children == 3, for example
session.add(Child(father_id=parent_id))
session.flush()
new_num_children = len(parent.children)
# num_children == 3, it should be 4!
非常感谢任何帮助!
我可以直接将新子项添加到parent.children
列表,然后刷新会话,但由于其他现有代码,我想使用session.add
添加它。
我可以在添加孩子之后commit
,它正确更新parent.children
关系,但我不想在此时提交交易。
我尝试在backref
关系中添加children
,但这似乎没有任何区别。
答案 0 :(得分:1)
我自己遇到了这个问题。 SQLAlchemy会做一些内部记录,以防止每次访问关系时发出新的SQL查询。问题在于,似乎没有意识到直接更新外键可能会对关系产生影响。虽然SQLAlchemy可能可以通过修补来处理简单的连接,但对于复杂的连接却非常困难,我想这就是为什么它会像以前那样工作。
执行session.flush()
时,您会将更改发送回数据库,但是SQLAlchemy并未意识到需要查询数据库以更新关系。
如果在刷新后调用session.expire_all()
,那么您将强制SQLAlchemy在下次访问它们时重新加载每个模型实例和关系-这样就解决了问题。
您还可以使用session.expire(obj)
来有选择地执行此操作,或者使用session.refresh(obj)
来有选择地执行此操作,然后立即重新查询数据库。
有关这些方法及其区别的更多信息,我找到了一篇有用的博客文章:https://www.michaelcho.me/article/sqlalchemy-commit-flush-expire-refresh-merge-whats-the-difference