
本文将深入探讨 SQLAlchemy 中如何正确建立和查询父子关系,解决在未提交或刷新会话之前,父对象无法自动获取子对象的问题,并提供两种有效的解决方案,确保关系数据的一致性和完整性。
在使用 SQLAlchemy ORM 构建数据库模型时,经常需要定义表之间的关系,例如父子关系。 然而,在某些情况下,即使定义了关系,也可能无法立即从父对象访问到子对象。这是因为 SQLAlchemy 默认情况下不会立即加载关系数据,而是在需要时才进行加载。
以下面的代码为例,展示了这个问题:
from sqlalchemy.orm import declarative_base, relationshipfrom sqlalchemy import Column, String, Integer, ForeignKeyBase = declarative_base()class Parent(Base): __tablename__ = 'parents' id = Column(Integer, primary_key=True) name = Column(String(20)) children = relationship('Child', back_populates='parent')class Child(Base): __tablename__ = 'children' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parents.id')) name = Column(String(20)) parent = relationship('Parent', back_populates='children')
在上述代码中,Parent 类和 Child 类之间建立了父子关系。Parent 类通过 children 属性关联到 Child 类,而 Child 类通过 parent 属性关联到 Parent 类。
然而,如果在将对象添加到会话之前尝试访问父对象的子对象,会发现子对象列表为空。
mother = Parent(id=1, name='Sarah')c1 = Child(id=22, parent_id=mother.id, name='Alice')c2 = Child(id=23, parent_id=mother.id, name='Bob')print(mother.children) # 输出: []
这是因为 SQLAlchemy 在将对象添加到会话并刷新或提交之前,不会自动加载关系数据。要解决这个问题,有两种主要方法:
1. 刷新会话 (Flush)
刷新会话会将所有挂起的更改(包括添加、修改和删除对象)同步到数据库,但不会提交事务。 刷新后,关系数据将被加载,可以从父对象访问到子对象。
import sysfrom sqlalchemy import ( create_engine, Integer, String,)from sqlalchemy.schema import ( Column, ForeignKey,)from sqlalchemy.orm import declarative_base, Session, relationshipBase = declarative_base()# 假设已配置好数据库连接# username, password, db = sys.argv[1:4]# engine = create_engine(f"postgresql+psycopg2://{username}:{password}@/{db}", echo=False)engine = create_engine('sqlite:///:memory:', echo=True) # 使用内存数据库方便演示class Parent(Base): __tablename__ = "parents" id = Column(Integer, primary_key=True) name = Column(String) children = relationship('Child', back_populates='parent')class Child(Base): __tablename__ = "childs" id = Column(Integer, primary_key=True) name = Column(String) parent_id = Column(Integer, ForeignKey('parents.id')) parent = relationship('Parent', back_populates='children')Base.metadata.create_all(engine)with Session(engine) as session: mother = Parent(id=1, name='Sarah') c1 = Child(id=22, parent_id=mother.id, name='Alice') c2 = Child(id=23, parent_id=mother.id, name='Bob') session.add(mother) session.add(c1) session.add(c2) # 在刷新之前,mother.children 为空 print(f"Before flush: {mother.children}") # 输出: Before flush: [] session.flush() # 刷新后,mother.children 将包含 c1 和 c2 print(f"After flush: {mother.children}") # 输出: After flush: [, ] session.commit() # 提交事务,将更改保存到数据库
2. 手动建立关系
可以在创建对象时手动建立父子关系,将子对象添加到父对象的 children 列表中。 这样,即使在刷新会话之前,也可以从父对象访问到子对象。
import sysfrom sqlalchemy import ( create_engine, Integer, String,)from sqlalchemy.schema import ( Column, ForeignKey,)from sqlalchemy.orm import declarative_base, Session, relationshipBase = declarative_base()# 假设已配置好数据库连接# username, password, db = sys.argv[1:4]# engine = create_engine(f"postgresql+psycopg2://{username}:{password}@/{db}", echo=False)engine = create_engine('sqlite:///:memory:', echo=True) # 使用内存数据库方便演示class Parent(Base): __tablename__ = "parents" id = Column(Integer, primary_key=True) name = Column(String) children = relationship('Child', back_populates='parent')class Child(Base): __tablename__ = "childs" id = Column(Integer, primary_key=True) name = Column(String) parent_id = Column(Integer, ForeignKey('parents.id')) parent = relationship('Parent', back_populates='children')Base.metadata.create_all(engine)with Session(engine) as session: c1 = Child(id=22, name='Alice') c2 = Child(id=23, name='Bob') mother = Parent(id=1, name='Sarah', children=[c1, c2]) # 手动建立关系 session.add(mother) session.add(c1) session.add(c2) # 在刷新之前,mother.children 已经包含 c1 和 c2 print(f"Before flush: {mother.children}") # 输出: Before flush: [, ] session.flush() # 刷新后,关系数据仍然有效 print(f"After flush: {mother.children}") # 输出: After flush: [, ] session.commit() # 提交事务,将更改保存到数据库
注意事项:
手动建立关系时,需要确保父对象的 id 已经存在,或者在创建子对象时同时创建父对象。在使用 relationship 时,需要设置 back_populates 参数,以便 SQLAlchemy 能够正确地维护父子关系。
总结:
在 SQLAlchemy 中,要正确获取父子关系中的对象,需要在将对象添加到会话后,刷新会话或手动建立关系。 选择哪种方法取决于具体的需求和场景。 如果需要在刷新会话之前访问关系数据,则应手动建立关系。 否则,刷新会话是更简单和更常用的方法。 务必理解 SQLAlchemy 的会话管理和关系加载机制,以便编写更高效和更可靠的代码。
以上就是SQLAlchemy:如何获取“子”类中的对象?的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1371502.html
微信扫一扫
支付宝扫一扫