刷新后SQLAlchemy关系未更新

时间:2018-06-14 20:55:00

标签: python sqlalchemy

我有一些模型,它们之间的关系定义如下:

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,但这似乎没有任何区别。

1 个答案:

答案 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

官方文档:https://docs.sqlalchemy.org/en/13/orm/session_api.html