スポンサーリンク
概要
SQLAlchemy2.0で、多対多のリレーションがるデータで存在しないデータのみをInsertしたい場合のメモ。
スポンサーリンク
説明
詳細
下記のような多対多のリレーションを持つデータがあるとする。(書籍、タグデータ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
from sqlalchemy import String from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column class Base(DeclarativeBase): pass class Tag(Base): __tablename__ = "tags" id: Mapped[int] = mapped_column(Integer, primary_key=True) # 略 class Book(Base): __tablename__ = "books" id: Mapped[int] = mapped_column(Integer, primary_key=True) tags: Mapped[list[Tag]] = relationship(secondary=books_publishers_association_table) # 略 books_tags_association_table = Table( "books_tags_association_table", Base.metadata, Column("books_id", ForeignKey("books.id")), Column("tags_id", ForeignKey("tags.id")), ) |
このようなデータに対して、書籍データを新規作成する際に、新規のタグと既存のタグが混在しており、存在しないタグのみをINSERTしたいとする。
下記のように、一度リレーションを持つデータをDBに問い合わせて、既に存在するデータを取り出し、そちらをaddしたいデータのlistに追加する。
そして、存在しないデータ(INSERTしたいもの)のみをlistに追加すれば良い。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class SqlBookRepository(): _session: Session def create(self, item: BookData): book = convert_dto(item) # Bookクラスのデータを生成 original = book.tag # 変更前の値を保持 # tagsのデータをDBに問い合わせ book.tags = ( self._session.query(Tags).filter(Tags.id.in_([tag.id for tag in book.tags])).all() ) # DBに存在しないデータを追加 for original in originals: matched = next((t for t in book.tags if t.id == original.name), None) if matched is None: book.tags.append(original) self._session.add(book) self._session.commit() |