我正在尝试使用 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”表仅与现有的“经济学家”相关联
现在想知道这是否是我问题的关键......
但是,我不确定如何自动执行此操作。
最终起作用的是父级关系表(在我的例子中为 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() 来解决的