前回、テーブル間のリレーションを考慮しないJOINについて学習しました。今回はテーブルクラスにリレーションを定義する方法とそれらが考慮されたJOINについて学習しましょう。
relationshipとjoin
あるテーブルのレコードに対して、別のテーブルのレコードが複数紐づくようなリレーションです。例えば、ブログシステムにおけるユーザーと投稿の関係などがこれに該当しますね。子テーブルに外部キーを定義し、親テーブルクラス内で以下のようにrelationship関数を使用します。
子属性 = relationship("子テーブル")
前回のサンプルにOne To Manyのリレーション定義を追加したサンプルを見てみましょう。
from sqlalchemy import Table, Column, Integer, ForeignKey, String
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# DB接続
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
posts = relationship("Post", backref="users") # Postとのリレーション
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
users_id = Column(Integer, ForeignKey('users.id'))
title = Column(String)
body = Column(Integer)
user = relationship("User") # Userとのリレーション
# テーブルクラスのテーブルを生成
Base.metadata.create_all(engine)
# セッション生成
Session = sessionmaker(bind=engine)
session = Session()
# サンプルデータ挿入
session.add(User(id=1, name="Suzuki", age=19))
session.add(User(id=2, name="Tanaka", age=21))
session.add(User(id=3, name="Sato", age=21))
session.add(Post(users_id=1, title="朝の体操", body="ラジオ体操で元気いっぱい"))
session.add(Post(users_id=1, title="今日の夕食", body="カレーラスがとても美味しかった。"))
session.add(Post(users_id=2, title="仕事", body="今日はDjangoでAPI作成。"))
session.add(Post(users_id=2, title="Python楽しい", body="Python楽しいですよね!!"))
session.commit()
# inner joinのサンプル
users = session.query(User).join(Post, User.id == Post.users_id).all()
for user in users:
print("%sさんの投稿" % (user.name))
for post in user.posts:
print("|- タイトル:%s" % (post.title,))
print('')
以下のような実行結果が得られます。前回のサンプルと異なり、結果オブジェクトが階層化されていることが確認できます。
Suzukiさんの投稿 |- タイトル:朝の体操 |- タイトル:今日の夕食 Tanakaさんの投稿 |- タイトル:仕事 |- タイトル:Python楽しい
また、relationship関数の引数にback_populates、backref、uselistなどの引数を指定することにより、関係の双方向性やユニーク性を定義することができます。これらの組み合わせによりOne To Many、Many To One、One To One、Many To Many、アソシエーションといった関係を定義することができます。
