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

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

新規登録して質問してみよう
ただいま回答率
85.48%
SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

6460閲覧

sqlalchemyで外部キーを使いたいが上手くできない

universegift77

総合スコア12

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/11/07 04:24

編集2020/11/07 05:09

fastapiを使っています。DBは現状sqliteで開発をしています。

外部キーを使いたいのですが、公式サイトを読んだり日本語の記事を読んだりしてもイマイチ理解できていません。

models.pyコードは以下です。

python

1from sqlalchemy import Boolean,Column,ForeignKey,Integer,String 2from sqlalchemy.orm import relationship 3 4class Parenttest(Base): 5 __tablename__="oya" 6 id=Column(Integer,primary_key=True,unique=True) 7 kodomox=relationship("Childstest",back_populates="oyax") 8 9class Childstest(Base): 10 __tablename__="kodomo" 11 id=Column(Integer,primary_key=True,unique=True) 12 oyanoid=Column(Integer,ForeignKey("oya.id")) 13 oyax=relationship("Parenttest",back_populates="kodomox") 14 15

このDBに対する操作が以下です。
以下のコードでは「参照している外部テーブルに存在しない値」を外部キーに保存しようとしているのでエラーになることを期待しています。

python

1#Parenttestに一つ登録。 2db_test=models.Parenttest() 3db.add(db_test) 4db.commit() 5 6#Childstestに(外部参照先のParenttestに存在しない)IDで登録。 7db_child=models.Childstest(oyanoid=200) 8db.add(db_child) 9db.commit() 10 11

しかし、なぜかこれが成功してしまいます。
外部キー制約が機能していればoyaテーブルに存在しない値を保存できないはずではないでしょうか?

質問は以下です。
0. oyaxとかkodomoxとかに設定したrelationshipはどこで使われているのか。(僕は最初、ForeignKey("oyax.id")のようにして使うのだと思っていたのですが、ForeignKeyの引数には"テーブル名.カラム名"をとるようです)
0. 存在しない値を登録できてしまうのは何故か。登録できないようにDBを設計する方法はあるのか。
0. relationshipの行を全てコメントアウトしてしまっても動いてしまった(登録できてしまった)が、ここはなんの意味があるのか。

質問のうち分かるものだけでも結構です。どうか教えてください

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

SQLAlchemyはそれほど詳しくはないのですが。
(ForeignKeyは「なんか、他のテーブルを参照するやつだよねー」ぐらいの認識しかなかったので、これを気にちょっと調べました)

存在しない値を登録できてしまうのは何故か。登録できないようにDBを設計する方法はあるのか。

もしSQLiteを使っているのであれば、デフォルトで有効になっていないそうですよ。

以下のようにPRAGMAを実行したら、確かにkodomoへの追加でエラーになりました。

python

1engine = create_engine('sqlite:///:memory:', echo=True) 2engine.execute('PRAGMA foreign_keys = true;')

relationshipは、(あまり良く知っているわけではないのであれですが)いわば「便利機能」です。別になくても構いません。
relationshipのメンバにアクセスすると、勝手にクエリーを実行して適切な値を設定します。

例えば、

python

1parent = Parenttest() 2parent.kodomox = [Childstest()] 3db.add(parent) 4db.commit()

とすれば、

2020-11-07 18:37:54,678 INFO sqlalchemy.engine.base.Engine INSERT INTO oya DEFAULT VALUES 2020-11-07 18:37:54,678 INFO sqlalchemy.engine.base.Engine () 2020-11-07 18:37:54,679 INFO sqlalchemy.engine.base.Engine INSERT INTO kodomo (oyanoid) VALUES (?) 2020-11-07 18:37:54,679 INFO sqlalchemy.engine.base.Engine (1,) 2020-11-07 18:37:54,679 INFO sqlalchemy.engine.base.Engine COMMIT

というように、parentと同時にparent.kodomoxのデータも追加されますし、

python

1print(db.query(Parenttest).one().kodomox[0].oyanoid)

というように、kodomoxの属性にアクセスすると、

2020-11-07 18:37:54,680 INFO sqlalchemy.engine.base.Engine SELECT oya.id AS oya_id FROM oya 2020-11-07 18:37:54,680 INFO sqlalchemy.engine.base.Engine () 2020-11-07 18:37:54,682 INFO sqlalchemy.engine.base.Engine SELECT kodomo.id AS kodomo_id, kodomo.oyanoid AS kodomo_oyanoid FROM kodomo WHERE ? = kodomo.oyanoid 2020-11-07 18:37:54,682 INFO sqlalchemy.engine.base.Engine (1,)

というように、kodomoテーブルへのクエリーも自動的に実行します。

(知っているかもしれませんが、create_engineに「echo=True」のオプションを指定すると、上記のように実行するSQL文も出力されるので、非常に参考になります)

投稿2020/11/07 09:46

katsuko

総合スコア3471

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問