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

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

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

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

SQLite

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

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

Q&A

解決済

1回答

2959閲覧

SQLAlchemyにおいての重複データのupsert

DoryHeadech

総合スコア2

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

SQLite

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

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

0グッド

2クリップ

投稿2022/04/29 15:14

flaskでwebアプリ制作しながらプログラミングの勉強をしています
現在持っているデータをどのようにdbに登録すればいいのか、お教えください。

使用
  1. Flask-SQLAlchemy
  2. sqllite3

持っているデータ

titleactmaker
タイタニックディカプリオ20世紀fox
タイタニックケイト・ウィンスレット 20世紀fox
アイアンマンRobert John Downey Jr.パラマウント
アイアンマングウィネス・パルトローパラマウント
アイアンマン3Robert John Downey Jr.ディズニー
アベンジャーズRobert John Downey Jr.ディズニー

想定したdbの設定

  1. titleーact ; many to many → 中間テーブル(appearance)
  2. title-maker ; one to many

flaskSQLAlchemyのドキュメントを参考に

appearance = db.Table('appearance', db.Column('act_id', db.Integer, db.ForeignKey('act.id'), primary_key=True), db.Column('detail_id', db.Integer, db.ForeignKey('detail.id'), primary_key=True)) class Act(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50),unique=True) class Maker(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50),unique=True) class Detail(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(80), nullable=False,unique=True) act = db.relationship("Act",secondary=appearance) maker_id = db.Column(db.Integer, db.ForeignKey('maker.id')) maker = db.relationship('Maker', backref=db.backref('makers', lazy=True)) d=Detail(title=t, maker=m,act=[a]) db.session.add(s) db.session.commit()

このように設定しました。
次にデータを登録するために

for文で回して登録しようと思い

s=Detail(title=t, maker=m,act=[a]) db.session.add(s)

試してみると重複のため登録できませんでした
色々、調べて2つの方法を試しました。

ユニーク制約を外す

ユニーク制約を外すと重複されて登録されてしまう
→リレーションdbの意味がない?持っているデータとあまり変わらない?

upsertで登録作業をする

def upsert_stmt(): stmt = insert(Detail) return stmt.on_conflict_do_update( index_elements=['id'], set_={ 'title': stmt.excluded.title, 'maker': stmt.excluded.maker, 'act': stmt.act }) db.session.execute(stmt) #エラー IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed db.session.add(stmt) #エラー UnmappedInstanceError: Class 'sqlalchemy.dialects.postgresql.dml.Insert' is not mapped

https://qiita.com/nsuhara/items/86570f789093222252b1

def suffix_insert(insert, compiler, **kwargs): stmt = compiler.visit_insert(insert, **kwargs) if insert.dialect_kwargs.get('sqlite_on_conflict_do_nothing'): stmt += ' ON CONFLICT DO NOTHING' return stmt Insert.argument_for('sqlite', 'on_conflict_do_nothing', False) some_random_values = detail stmt = db.insert(Detail, sqlite_on_conflict_do_nothing=True).values(some_random_values) db.session.execute(stmt) #エラー CompileError: Unconsumed column names

https://stackoverflow.com/questions/64900812/how-to-use-sqlites-upsert-or-on-conflict-with-flask-sqlalchemy
→リレーション関係ところの設定がうまくいっていない?

upsertの方法はエラーがでてうまくいきませんでした

質問は
重複をもつデータのリレーションな関係で登録する方法です。
どうすれば、簡単に登録できるのかお願い致します。
(そもそもの方向性があっているのか、もし間違っていたらそのプロセスもお教えください。)

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

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

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

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

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

68user

2022/04/30 15:29 編集

そもそも何がしたいのかがいまいちつかめないのですが、持っているデータは非正規形であるので DB は正規化したいんですよね。しかし Detail は非正規形? 持っているデータから、  title_id, title  act_id, act  maker_id, maker  + 紐づけテーブル なデータを作って、それを各テーブルに突っ込んで、Detail は作らない、ではダメなんでしょうか。 ↑のデータを作るとは以下のようなものを想定しています。別に DB を絡めなくても、データを順に舐めて新しいものが出てきたら通番を振るだけ (dict などで管理する)。 title_id, title 1:タイタニック 2:アイアンマン 3:アイアンマン3 act_id, act 1:ディカプリオ 2:ケイト・ウィンスレット  3:Robert John Downey Jr. 4:グウィネス・パルトロー 上記ができたら title テーブルなり act テーブルなりに突っ込むだけ。
guest

回答1

0

ベストアンサー

答えではありませんが、修正依頼に画像が貼り付けられないので、こちらに。

とりあえず提示のモデルを使ってdb作ってみたら以下の画像のようになりました。

イメージ説明

持っているデータとして提示いただいているテーブルのタイトル(カラム名)と、detailの「列」が一致していないように感じますが、想定通りですか?

作成されるテーブル4つなのに、持っているデータは1テーブルしか提示されていないので、データ作るのが面倒でこれ以上の確認は断念しました・・・。

E-R図をリバース生成したらこんな感じでした。(MariaDB)
こちらも想定通りですか?
イメージ説明

SQLiteのE-R図を作成したところ、keyは同じでしたが、リレーション(線)が皆無でした。(ツールが対応していないだけかもしれませんが。)

投稿2022/05/06 09:23

FiroProchainezo

総合スコア2401

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

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

DoryHeadech

2022/05/08 09:34

図など詳細にコメントしていただきありがとうございます。 gwだったのでプログラミング学習の時間が取れずじまいで回答に気づきませんでした。 回答への返事が遅れてしまったことをお詫び申し上げます。 持っているデータは、スクレイピングでとってきた表で、 dbに格納していくイメージでした。 dbの設定もドキュメントのものを一部改変しただけなのでよく意味も分かっていません。ただ、回答を読ませていただくと設定自体の設計ミスだったみたいですね。 設定方法などまだよくわかっていないようなのでもうちょっと勉強してから設定をやり直してみたいと思います。 この度は、コメント本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問