在使用 SQLAlchemy 进行数据库映射时,可能会遇到需要跨多张表创建关联关系的情况。例如,您可能需要在表 A 和表 C 之间建立关联关系,但表 A 和表 C 之间没有直接的关联关系,而是通过表 B 建立关联。
解决方案
在 SQLAlchemy 中,可以通过使用 relationship()
函数来创建跨多张表的关联关系。relationship()
函数可以指定关联关系的类型、关联表的名称以及关联条件。
下面是一个示例,演示如何在 SQLAlchemy 中创建跨多张表的关联关系:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(Integer, ForeignKey('b.id'))
cs = relationship("C",
# C.id is "foreign" because there can be many C.ids for one A.id
# B.id is "remote", it sort of means "this is where the stuff
# starts that's not directly part of the A side"
primaryjoin="and_(A.b_id == remote(B.id), foreign(C.id) == B.c_id)",
viewonly=True)
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
c_id = Column(Integer, ForeignKey('c.id'))
class C(Base):
__tablename__ = 'c'
id = Column(Integer, primary_key=True)
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
sess = Session(e)
sess.add(C(id=1))
sess.flush()
sess.add(B(id=1, c_id=1))
sess.flush()
sess.add(A(b_id=1))
sess.flush()
a1 = sess.query(A).first()
print(a1.cs)
在这个示例中,我们首先定义了三个类 A
、B
和 C
,分别对应于表 A、表 B 和表 C。然后,我们在类 A
中定义了一个名为 cs
的关联关系,该关联关系指向表 C
。在 primaryjoin
参数中,我们指定了关联条件,该条件为 and_(A.b_id == remote(B.id), foreign(C.id) == B.c_id)
。这意味着,表 A 中的 b_id
列与表 B 中的 id
列相关联,而表 B 中的 c_id
列与表 C 中的 id
列相关联。
最后,我们创建了一个 SQLAlchemy Session
对象,并使用该对象添加了一些数据到表 A、表 B 和表 C 中。然后,我们就可以使用 a1.cs
来访问表 A 中的 id
为 1 的记录所关联的表 C 中的记录。
代码示例
# 导入必要的类
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
# 定义基类
Base = declarative_base()
# 定义表 A 的类
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
b_id = Column(Integer, ForeignKey('b.id'))
# 定义关联关系
cs = relationship("C",
# C.id is "foreign" because there can be many C.ids for one A.id
# B.id is "remote", it sort of means "this is where the stuff
# starts that's not directly part of the A side"
primaryjoin="and_(A.b_id == remote(B.id), foreign(C.id) == B.c_id)",
viewonly=True)
# 定义表 B 的类
class B(Base):
__tablename__ = 'b'
id = Column(Integer, primary_key=True)
c_id = Column(Integer, ForeignKey('c.id'))
# 定义表 C 的类
class C(Base):
__tablename__ = 'c'
id = Column(Integer, primary_key=True)
# 创建数据库引擎
e = create_engine("sqlite://", echo=True)
# 创建所有表
Base.metadata.create_all(e)
# 创建一个 SQLAlchemy Session 对象
sess = Session(e)
# 添加一些数据到表中
sess.add(C(id=1))
sess.flush()
sess.add(B(id=1, c_id=1))
sess.flush()
sess.add(A(b_id=1))
sess.flush()
# 查询表 A 中的记录
a1 = sess.query(A).first()
# 打印表 A 中的记录所关联的表 C 中的记录
print(a1.cs)
输出:
[<C(id=1)>]