SQLAlchemy 如何获取“子”类中的对象?

SQLAlchemy 如何获取“子”类中的对象?

本文介绍了在使用 SQLAlchemy 进行数据库操作时,如何正确地获取父类关联的子类对象。重点在于理解 SQLAlchemy 的关系(relationship)以及何时进行 flush 操作,以确保对象之间的关联关系被正确地建立和加载。通过示例代码,演示了两种实现方式,帮助开发者避免常见的关系映射问题。

在使用 SQLAlchemy 进行对象关系映射(ORM)时,经常需要在父类对象中获取关联的子类对象。然而,初学者可能会遇到类似“无法立即获取到关联子对象”的问题。这是因为 SQLAlchemy 的关系(relationship)在默认情况下,并不会立即加载所有关联对象。需要理解 SQLAlchemy 的 session 管理和 flush 机制,才能正确地获取和操作这些关联对象。

理解 SQLAlchemy 的 Relationship

在 SQLAlchemy 中,relationship 用于定义表之间的关系。例如,一个 Parent 类可以拥有多个 Child 类实例,而 Child 类实例又关联到一个 Parent 类实例。back_populates 参数用于指定反向引用,使得可以通过 parent.children 和 child.parent 访问关联对象。

from sqlalchemy.orm import declarative_base, relationship from sqlalchemy import Column, String, Integer, ForeignKey  Base = 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')

延迟加载与 Flush 操作

默认情况下,SQLAlchemy 的 relationship 使用延迟加载(lazy loading)。这意味着,只有在真正访问 parent.children 属性时,才会执行数据库查询来加载子对象。 更重要的是,即使你创建了 Parent 和 Child 对象,并将它们添加到 Session 中,它们之间的关系也不会立即建立。需要执行 session.flush() 操作,才能将对象的更改刷新到数据库,并建立对象之间的关系。

示例代码

以下示例展示了两种获取关联子对象的方法:

SQLAlchemy 如何获取“子”类中的对象?

ChatDOC

ChatDOC是一款基于chatgpt的文件阅读助手,可以快速从pdf中提取、定位和总结信息

SQLAlchemy 如何获取“子”类中的对象?178

查看详情 SQLAlchemy 如何获取“子”类中的对象?

方法一:先添加到 Session,然后 Flush

from sqlalchemy import create_engine from sqlalchemy.orm import Session  # 假设你已经定义了 Parent 和 Child 类,并创建了 engine engine = create_engine('sqlite:///:memory:', echo=True) # 使用内存数据库方便演示 Base.metadata.create_all(engine) # 创建表  def test1():     with Session(engine) as session:         mother = Parent(name='Sarah')         c1 = Child(name='Alice')         c2 = Child(name='Bob')          # 关键:将 parent_id 设置为 mother.id         c1.parent = mother         c2.parent = mother          # 添加到 Session         session.add(mother)         session.add(c1)         session.add(c2)          # 刷新 Session,将更改同步到数据库         session.flush()          # 现在 mother.children 包含了 c1 和 c2         print(mother.children)         assert len(mother.children) == 2         assert c1.parent == mother         assert c2.parent == mother  test1()

方法二:在创建 Parent 对象时,直接关联 Child 对象

from sqlalchemy import create_engine from sqlalchemy.orm import Session  # 假设你已经定义了 Parent 和 Child 类,并创建了 engine engine = create_engine('sqlite:///:memory:', echo=True) # 使用内存数据库方便演示 Base.metadata.create_all(engine) # 创建表  def test2():     with Session(engine) as session:         c1 = Child(name='Alice')         c2 = Child(name='Bob')          # 在创建 Parent 对象时,直接将 children 关联         mother = Parent(name='Sarah', children=[c1, c2])          # 添加到 Session         session.add(mother)         session.add(c1)         session.add(c2)          # 刷新 Session,将更改同步到数据库         session.flush()          # 现在 mother.children 包含了 c1 和 c2         print(mother.children)         assert len(mother.children) == 2         assert c1.parent == mother         assert c2.parent == mother  test2()

注意事项

  1. session.flush() 的作用: flush() 操作将 Session 中的更改同步到数据库,但不提交事务。这意味着,如果后续操作失败,可以回滚事务,撤销这些更改。
  2. session.commit() 的作用: commit() 操作提交事务,将更改永久保存到数据库。
  3. 显式设置关系: 确保在将对象添加到 Session 之前,显式地设置对象之间的关系(例如,通过 child.parent = parent 或在创建 Parent 对象时,直接将 Child 对象添加到 children 列表中)。
  4. 数据库引擎的选择: 在示例中使用了内存数据库 sqlite:///:memory:,这方便了演示,但实际应用中需要根据需求选择合适的数据库引擎。
  5. 延迟加载的影响: 理解延迟加载的机制,可以避免不必要的数据库查询,提高性能。如果需要立即加载关联对象,可以使用 joinedload 等加载策略。

总结

要正确地获取 SQLAlchemy 中父类关联的子类对象,需要理解 relationship 的定义、session.flush() 的作用,以及显式地设置对象之间的关系。通过合理地使用这些机制,可以有效地管理对象之间的关联关系,并编写出高效、可维护的数据库应用程序。

session 延迟加载 父类 子类 Session 对象 sqlite 数据库

上一篇
下一篇