2023年4月25日火曜日

SQLAlchemyのdb.queryで複数のテーブル(クラス)を指定した場合の挙動

SQLAlchemyのdb.queryで複数のテーブル(クラス)を指定した場合の挙動

概要

結合後に結合した複数のテーブル情報を取得したい場合には all や first の返り値が少し変わるので操作に工夫が必要になります

環境

  • macOS 11.7.4
  • SQLAlchemy 2.0.7

SQL例

def list_user_by_sub_group_name(self, name: str) -> list[User|Group]:
    return (
        self.db.query(User, Group)
        .join(Group, User.group_id == Group.id)
        .join(SubGroup, Group.sub_group_id == SubGroup.id)
        .filter(
            SubGroup.name == name,
        )
        .all()
    )

db.query で User クラスと Group テーブルを指定します
こうすることで user テーブルと group テーブルが結合された特殊な行データ (sqlalchemy.engine.row.Rowというクラス)のデータが取得できます

Row の扱い方

配列には各テーブルごとにタプルとして格納されています

rows = self.list_user_by_sub_group_name("subgroup1")
for row in rows:
    user = row[0]  # db.query の 1 つ目の引数で指定したクラスのデータがタプルの index=0 に格納されている
    group = row[1]  # db.query の 2 つ目の引数で指定したクラスのデータがタプルの index=1 に格納されている
    print(user.id)
    print(group.id)

注意事項

pyright などを使って型チェックしていると "__getitem__" method not defined on type "User" というエラーが出ます
素直に __getitem__ を実装するか # type: ignore で型チェックを無視するようにしましょう

最後に

ちょっと特殊な扱い方なので注意しましょう

0 件のコメント:

コメントを投稿