ForeignKeyを正しく設定しているのにsqlalchemy.exc.NoReferencedTableErrorが出る
Kazuki Moriyama (森山 和樹)
本来の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を修正すれば治る。