--- lang: ja-jp tags: Python, SQLAlchemy --- # SQLAlchemy relationship ## Basic Relationship Patterns [SQLAlchemy: Relationship Configuration > Basic Relationship Patterns](https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html) エンティティ同士の関係の定義の方法についての概要をみていきます。 後続のセクションでは次のインポートが記述されていることを前提とします。 ```python= from sqlalchemy import Table, Column, Integer, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() ``` ### One To Many **親が複数の子を持ちうるパターン** 1:N関係では親テーブルを参照する子テーブルに外部キーを設定します。次に`relationship()`を親テーブルに設定し、子テーブルが表現するアイテムの集合を参照するようにします。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) children = relationship('Child') class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) ``` 上の設定により、特定の`parent_id`を参照する子テーブルのエンティティを親テーブルから取得することができるようになります。 1:N関係において双方向の参照を実現するには、`relationship()`に`back_populates`パラメータを指定します。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) children = relationship('Child') class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship('Parent', back_populates='children') ``` これにより`Child`では`parent`属性を通じてN:1関係にある親テーブルのエンティティを取得することができるようになりました。 上の例では子テーブルのエンティティの定義の中で`N:1`の関係を記述しました。逆に、親テーブルのエンティティの定義において子が1つの親を持つという関係を記述する方法も用意されており、その場合には`relationship.backref`パラメータを指定します。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) # Childの属性として`parent`を動的に設定する children = relationship('Child', backref='parent') ``` :::info `relationship.backref`パラメータを指定して双方向の関係を記述する場合、子テーブルのエンティティの定義から`parent`の属性が存在することが明確ではないため、`relationship.back_populates`を利用する方が個人的には好ましいと考える。 ::: ### Many To One **子が複数の親を持ちうるパターン** N:1関係では子テーブルを参照する親テーブルにおいて外部キーを設定します。`relationship()`関数は親テーブルにおいて定義され、子テーブルのエンティティに対する参照を表現する属性値はスカラー値となります。 ```python= # 親は一つの子を持ち、子は複数の親を持ちうる class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child_id = Column(Integer, ForeignKey('child.id')) child = relationship('Child') class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) ``` 双方向の参照を定義するには、[One-To-Many](#One-To-Many)の場合と同様に`relationship.back_populates`パラメータを指定します。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child_id = Column(Integer, ForeignKey('child.id')) child = relationship('Child', back_populates='parents') class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parents = relationship('Parent', back_populates='child') ``` `relationship.backref`パラメータを指定して記述する方法もあります。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child_id = Column(Integer, ForeignKey('child.id')) child = relationship('Child', backref='parents') ``` ### One To One 1:1関係は実質的に双方向のスカラー参照を持つものとして定義されます。この(参照の属性値がスカラーとなるような)挙動を実現するには、`relationship.uselist`フラグを指定します(外部キーを通して属性を参照**される**側の`relationship.uselist`を`False`に設定します)。 ```python= class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) child = relationship('Child', uselist=False, back_populates='parent') class Child(Base): __tablename__ = 'child' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) parent = relationship('Parent', back_populates='child') ```