508 views
B!0X

ForeignKeyを正しく設定しているのにsqlalchemy.exc.NoReferencedTableErrorが出る

foreignkey-sqlalchemy-exc-noreferencedtableerror

本来のsqlalchemy.exc.NoReferencedTableErrorの意味

このエラーはsqlalchemy ormのDeclarativeスタイルでのForeignKey定義が間違っているときに出る。
例えばForeignKeyの指定先の他のテーブルが存在しないときなど。

ただしその設定が正しい場合でもこのエラーが出る場合がある。

relationship()を正しく設定する

relationshipよってモデル間の関係性を定義できるが、その設定が間違っていると対象のモデルがどうも作成されないことがあるらしい。

例えば以下の例ではParent、Child、Hobyという3つのテーブルが有り、それらはrelationship定義によって相互に依存し合っている。

class Parent(Base):
    __tablename__ = "parent_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    children: Mapped[List["Child"]] = relationship(back_populates="parent")

class Child(Base):
    __tablename__ = "child_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"))
    parent: Mapped["Parent"] = relationship(back_populates="children")
    hobbies: Mapped[list["Hobby"]] = relationship(back_populates="child")

class Hobby(Base):
    __tablename__ = "hobby_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    child_id: Mapped[int] = mapped_column(ForeignKey("child_table.id"))
    child: Mapped["Child"] = relationship(back_populates="hobbies")

しかしここで仮にChildのrelationship定義が間違っていると、Childクラスのロード?が行われないらしく、そのせいでHobyで指定しているForeignKey("child_table.id")の参照先のカラムが存在しない、という判定を食らうらしい。

class Parent(Base):
    __tablename__ = "parent_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    children: Mapped[List["Child"]] = relationship(back_populates="parent")

class Child(Base):
    __tablename__ = "child_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"))
    # ここのback_populatesが間違っている
    parent: Mapped["Parent"] = relationship(back_populates="wrong")
    hobbies: Mapped[list["Hobby"]] = relationship(back_populates="child")

class Hobby(Base):
    __tablename__ = "hobby_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    child_id: Mapped[int] = mapped_column(ForeignKey("child_table.id"))
    child: Mapped["Child"] = relationship(back_populates="hobbies")

結果的にNoReferencedTableErrorが出ることがある。

おわり

かなりエスパーしているので理由については不確実だが、relationshipを修正すれば治る。

関連事例

  • データ分析支援

    事例:過去実績を提案に活用する分析の仕組み

    広告代理店との取り組みです。同社は過去実績の示唆を次の提案へ反映し、結果をどのように予測したか、その背景まで提案先のクライアントへ説明できるようになりました。KDOT は案ごとの見込みと判断材料を比較できる仕組みを業務アプリとして実装しました。さらに業務アプリの中核となる処理ロジックと機械学習モデルについて、特許手続きを担う弁理士が技術の新規性や工夫を検討するための資料を作成しました。その後この発明には特許が付与されました。

  • データ基盤構築 / 技術顧問(技術企業向け)

    事例:効果検証の分析処理基盤

    効果検証を提供する分析会社との取り組みです。同社は分析者の人数に比例してしか売上と利益を伸ばせない事業の形を、効果検証をプロダクトとして提供することで変革しようとしていました。手法とモデルは同社のまま、社内では開発できなかった、データと機械学習の重い推定を製品として動かす仕組みの開発を、開発支援会社の KDOT に任せました。推定を案件ごとの手作業ではなくシステムで実行できるようになったことで、同社は人数に比例しない形で売上と利益を伸ばすことを目指せるようになりました。

開発の相談先をお探しですか。

この記事に関わることについてご相談がある方はお問い合わせください。

KDOT についてお問い合わせ