SQLAlchemy可以通过关联表表达一对多关系吗?



我正在尝试使用SQLAlchemy访问现有的DB。(因此,我不能轻易地更改模式或现有数据。我也不确定为什么模式的结构是这样的。

考虑以下模式:

association_table = Table(
"association_table",
Base.metadata,
Column("child_id", ForeignKey("child_table.id"), primary_key=True),
Column("parent_id", ForeignKey("parent_table.id")),
)

class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship("Child", backref="parent", secondary=association_table)

class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)

在这个例子中,注意关联表中有一个主键。这应该建模一个一对多的关系(一个父节点对应一个子节点,一个父节点对应多个子节点),尽管对于这个目的来说关联表不是必需的。

然而,文档根本没有提到这一点。secondary只与多对多关系相关联,如果我将此模式转换为实际代码,父字段确实被创建为一个集合。

是否有办法说服SQLAlchemy从关联表中读取一对多关系?

你可以有一个二级表链接两个表在一对多的关系,你只需要有一个一对一的一面(与uselist=False)和一个一对多的一面。

但是,我想请您考虑一下为什么要增加这种复杂性。

完整的演示:

from sqlalchemy import Column, ForeignKey, Integer, Table, create_engine
from sqlalchemy.orm import Session, declarative_base, relationship
Base = declarative_base()

association_table = Table(
"association_table",
Base.metadata,
Column("parent_id", ForeignKey("parent_table.id"), primary_key=True),
Column("child_id", ForeignKey("child_table.id"), primary_key=True),
)

class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship(
"Child",
secondary=association_table,
back_populates="parent",
)

class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent = relationship(
"Parent",
secondary=association_table,
back_populates="children",
uselist=False,  # only one parent
)

engine = create_engine("sqlite://", echo=True, future=True)
Base.metadata.create_all(engine)
with Session(engine) as session:
alice = Parent()
bob = Child()
charlie = Child()
alice.children.extend([bob, charlie])
session.add(alice)
session.flush()

发出

CREATE TABLE parent_table (
id INTEGER NOT NULL, 
PRIMARY KEY (id)
)
CREATE TABLE child_table (
id INTEGER NOT NULL, 
PRIMARY KEY (id)
)
CREATE TABLE association_table (
parent_id INTEGER NOT NULL, 
child_id INTEGER NOT NULL, 
PRIMARY KEY (parent_id, child_id), 
FOREIGN KEY(parent_id) REFERENCES parent_table (id), 
FOREIGN KEY(child_id) REFERENCES child_table (id)
)
INSERT INTO child_table DEFAULT VALUES
INSERT INTO child_table DEFAULT VALUES
INSERT INTO parent_table DEFAULT VALUES
INSERT INTO association_table (parent_id, child_id) VALUES (1, 1), (1, 2)

最新更新