質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.78%

SQLAlchemyでForeignKeyのあるテーブルが作成できない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 406

score 809

前提・実現したいこと

  • SQLAlchemyを利用して、PosegreSQLのデータベースを作っています。
  • 外部キーを用いたテーブル作成がうまくいきません。下記の2つのテーブルを作りたいです。bs_secondaryテーブルは、外部キーとしてbs_primaryテーブルのidを参照させたいです。

(bs_primary)

id name
1 流動資産
2 固定資産
3 流動負債
4 固定負債
5 純資産

(bs_secondary)

id name primary_id
101 現金 1
102 当座預金 1
103 普通預金 1
  • まず最初にprimaryテーブルを作成しました。これは成功しました。
  • その後にsecondaryテーブルを作成しようとして、失敗しています。

発生している問題・エラーメッセージ

NoReferencedTableError                    Traceback (most recent call last)
<ipython-input-27-84edb30c4bec> in <module>
      9 
     10 
---> 11 Base.metadata.create_all(bind=engine)

~\Anaconda3\lib\site-packages\sqlalchemy\sql\schema.py in create_all(self, bind, tables, checkfirst)
   4002                           self,
   4003                           checkfirst=checkfirst,
-> 4004                           tables=tables)
   4005 
   4006     def drop_all(self, bind=None, tables=None, checkfirst=True):

~\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py in _run_visitor(self, visitorcallable, element, connection, **kwargs)
   1938                      connection=None, **kwargs):
   1939         with self._optional_conn_ctx_manager(connection) as conn:
-> 1940             conn._run_visitor(visitorcallable, element, **kwargs)
   1941 
   1942     class _trans_ctx(object):

~\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py in _run_visitor(self, visitorcallable, element, **kwargs)
   1547     def _run_visitor(self, visitorcallable, element, **kwargs):
   1548         visitorcallable(self.dialect, self,
-> 1549                         **kwargs).traverse_single(element)
   1550 
   1551 

~\Anaconda3\lib\site-packages\sqlalchemy\sql\visitors.py in traverse_single(self, obj, **kw)
    119             meth = getattr(v, "visit_%s" % obj.__visit_name__, None)
    120             if meth:
--> 121                 return meth(obj, **kw)
    122 
    123     def iterate(self, obj):

~\Anaconda3\lib\site-packages\sqlalchemy\sql\ddl.py in visit_metadata(self, metadata)
    734 
    735         collection = sort_tables_and_constraints(
--> 736             [t for t in tables if self._can_create_table(t)])
    737 
    738         seq_coll = [s for s in metadata._sequences.values()

~\Anaconda3\lib\site-packages\sqlalchemy\sql\ddl.py in sort_tables_and_constraints(tables, filter_fn, extra_dependencies)
   1093                     continue
   1094 
-> 1095             dependent_on = fkc.referred_table
   1096             if dependent_on is not table:
   1097                 mutable_dependencies.add((dependent_on, table))

~\Anaconda3\lib\site-packages\sqlalchemy\sql\schema.py in referred_table(self)
   3000 
   3001         """
-> 3002         return self.elements[0].column.table
   3003 
   3004     def _validate_dest_table(self, table):

~\Anaconda3\lib\site-packages\sqlalchemy\util\langhelpers.py in __get__(self, obj, cls)
    765         if obj is None:
    766             return self
--> 767         obj.__dict__[self.__name__] = result = self.fget(obj)
    768         return result
    769 

~\Anaconda3\lib\site-packages\sqlalchemy\sql\schema.py in column(self)
   1889                     "foreign key to target column '%s'" %
   1890                     (self.parent, tablekey, colname),
-> 1891                     tablekey)
   1892             elif parenttable.key not in parenttable.metadata:
   1893                 raise exc.InvalidRequestError(

NoReferencedTableError: Foreign key associated with column 'bs_secondary.bs_primary_id' could not find table 'bs_primary' with which to generate a foreign key to target column 'id'

該当のソースコード

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
engine = create_engine('postgresql://username:password@127.0.0.1:5432/database_name')

Base = declarative_base()

class BS_PRIMARY(Base):
    __tablename__ = 'bs_primary'

    id = Column(Integer, primary_key=True, autoincrement=False)
    name = Column(String)

Base.metadata.create_all(bind=engine)



上記までは成功しました。
下記を実行した所、上記のエラーが出ています。

Base = declarative_base()

class BS_SECONDARY(Base):
    __tablename__ = 'bs_secondary'

    id = Column(Integer, primary_key=True, autoincrement=False)
    name = Column(String)
    bs_primary_id = Column(Integer, ForeignKey("bs_primary.id"))    


Base.metadata.create_all(bind=engine)

対応策1

  • 一旦、bs_primaryを削除し、bs_primaryとbs_secondaryを同時に作成した所、作成することができました。
  • 後からリレーションの関係のあるテーブルを追加する方法があれば良いのですが、良い方法はあるのでしょうか。

何かお気づきの点ありましたら、ご教示頂ければ幸いです。
よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hoshi-takanori

    2020/06/02 05:03

    bs_primary と bs_secondary を別々に作ってるからでは。
    https://qiita.com/niwaringo/items/9277ec895c3ff94e5ade

    キャンセル

  • mulberryfields

    2020/06/02 08:11

    ありがとうございます。ご指摘の通り、同時に作成したら、出来ました。

    キャンセル

回答 1

check解決した方法

0

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *

engine = create_engine('postgresql://username:password@127.0.0.1:5432/database_name')

Base = declarative_base()

class BS_PRIMARY(Base):
    __tablename__ = 'bs_primary'

    id = Column(Integer, primary_key=True, autoincrement=False)
    name = Column(String)


# ここから追加
class BS_SECONDARY(Base):
    __tablename__ = 'bs_secondary'

    id = Column(Integer, primary_key=True, autoincrement=False)
    name = Column(String)
    bs_primary_id = Column(Integer, ForeignKey("bs_primary.id"))

# 最後にまとめてcreate_all
Base.metadata.create_all(bind=engine)

これでできました。
追記する時もBS_PRIMARYを記載しなければならないことと、最後にまとめてcreate_allという所が重要でした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る