我正在尝试使用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)