SQLAlchemy:具有两个主键的父级声明式多对多映射

问题描述 投票:0回答:1

我正在尝试使用 SQLAlchemy 声明多对多关系,其中我的父 RowHeader 可以通过关系表创建子经济学家。我不断遇到多个连接路径的错误,缺少声明的外键。我也遇到过创建子项违反主键约束的情况。我只想要一个孩子,但希望它与许多父母相关联。

row_econ_table = Table(
    "row_econ_table",
    Base.metadata,
    Column("rh_f_index", ForeignKey("row_header.f_index"), primary_key=True),  #left
    Column("rh_row", ForeignKey("row_header.row"), primary_key=True),   # left
    Column("econ_un_id", ForeignKey("economist.un_name_id"), primary_key=True),  #right
)
class RowHeader(Base):
    __tablename__ = "row_header"

    f_index: Mapped[str] = mapped_column(primary_key=True)
    row: Mapped[int] = mapped_column(primary_key=True)
    Names: Mapped[str] = mapped_column()
    Organization: Mapped[str] = mapped_column(nullable=True)
    economists: Mapped[List["Economist"]] = relationship(
        #cascade="all, delete",
        secondary=row_econ_table,
        foreign_keys=[f_index, row],
        primaryjoin="and_(RowHeader.f_index==row_econ_table.c.rh_f_index, " "RowHeader.row==row_econ_table.c.rh_row)",
        secondaryjoin="Economist.un_name_id==row_econ_table.c.econ_un_id"
    )
    def __repr__(self) -> str:
        return f"RowHeader(f_index={self.f_index!r}, row={self.row!r}, Names={self.Names!r}, Organization={self.Organization!r})"

class Economist(Base):
    __tablename__ = "economist"

    un_name_id: Mapped[str] = mapped_column(primary_key=True)

我的问题似乎是我的父级中有两个主键,它们创建了多个连接路径。我需要两个主键来使该表唯一。

我的目标是: 父级 (RowHeader) 通过关系表创建所有子级 (Economist)。如果不存在,则创建它。如果存在,则通过关系表与其建立关系。但是,不要创建同一个子项的多个。

我不确定我可以重新计算我尝试过多少种配置!!

我收到以下错误:

sqlalchemy.exc.ArgumentError: Could not locate any relevant foreign key columns for secondary join condition 'economist.un_name_id = row_econ_table.econ_un_id' on relationship RowHeader.economists.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.


sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship RowHeader.economists - there are no foreign keys linking these tables via secondary table 'row_econ_table'.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.

此外,我用它创建了一次表(忘记了创建此表的组合),但是当父级尝试创建一个已经存在的新子级时,我从子级中得到了主键约束错误。

更新:删除foreign_keys arg会导致表创建成功。所以,进步!

但是,当我尝试将对象添加到会话中,导致在已存在的“经济学家”表中创建一行时,我收到唯一约束错误并回滚。

sqlite3.IntegrityError: UNIQUE constraint failed: economist.un_name_id

我想我认为会话会为我处理这个问题,但如果我不添加全部并且一次只添加一个,也许会这样?我使用 SQLLITE 作为我的后端。不确定如何实现合并或使我的“row_header”表仅与现有的“经济学家”相关联

现在想知道这是否是我问题的关键......

ORM 更新插入语句

冲突时插入... (SQLLITE)

但是,我不确定如何自动执行此操作。

python sqlite sqlalchemy
1个回答
0
投票

最终起作用的是父级关系表(在我的例子中为 RowHeader)添加联接的一些更改。级联取决于用例。

economists: Mapped[List["Economist"]] = relationship(
        cascade="save-update",
        secondary=row_econ_table,
        #foreign_keys=[f_index, row],
        primaryjoin="and_(RowHeader.f_index==row_econ_table.c.rh_f_index, " "RowHeader.row==row_econ_table.c.rh_row)",
        secondaryjoin="Economist.un_name_id==row_econ_table.c.econ_un_id"
    )

这清除了不明确的连接。

在 IntegrityError 上,这是通过循环 session.merge() 而不是 session.add() 来解决的

© www.soinside.com 2019 - 2024. All rights reserved.