SQLAlchemyで宣言型を用いた1対1リレーションシップを作成する方法
SQLAlchemyで宣言型を用いた1対1リレーションシップの作成方法
この解説では、SQLAlchemyの宣言型を用いて、1対1リレーションシップを作成する方法を、コード例を交えて分かりやすく説明します。
1対1リレーションシップとは
1対1リレーションシップとは、1つのテーブルの各行が、別のテーブルの1つの行と関連付けられる関係です。
例えば、ユーザーテーブルとプロフィールテーブルがあるとします。この場合、1人のユーザーは1つのプロフィールを持つため、1対1リレーションシップが成立します。
宣言型を用いた1対1リレーションシップの作成
SQLAlchemyでは、declarative_base
クラスとrelationship
属性を用いて、宣言型で1対1リレーションシップを作成できます。
コード例
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship(User, back_populates='profile')
# 関係を定義
User.profile = relationship(Profile, uselist=False, back_populates='user')
コード解説
declarative_base
クラスからBase
クラスを継承します。User
クラスとProfile
クラスを定義します。User
クラスにはid
とname
属性、Profile
クラスにはid
とuser_id
属性を定義します。relationship
属性を用いて、User
クラスとProfile
クラスの関係を定義します。uselist=False
オプションを指定することで、1対1リレーションシップであることを明示します。back_populates
オプションを指定することで、逆方向の関係も定義します。
外部キー制約
上記のコード例では、Profile
クラスのuser_id
属性にForeignKey
制約を定義しています。
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship(User, back_populates='profile')
# エンジンとセッションの作成
engine = create_engine('sqlite:///example.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# ユーザーとプロフィールの作成
user = User(name='John Doe')
profile = Profile(user=user)
# データベースへの保存
session.add(user)
session.add(profile)
session.commit()
# ユーザー情報の取得
user = session.query(User).filter(User.name=='John Doe').first()
# プロフィール情報の取得
profile = user.profile
# セッションのクローズ
session.close()
create_engine
関数を使って、SQLiteデータベースへの接続を確立します。Base.metadata.create_all
メソッドを使って、データベースにテーブルを作成します。sessionmaker
関数を使って、セッションを作成します。relationship
属性を使って、User
クラスとProfile
クラスの関係を設定します。session.add
メソッドを使って、User
クラスとProfile
クラスのインスタンスをデータベースに追加します。session.commit
メソッドを使って、変更を保存します。session.query
メソッドを使って、User
クラスのインスタンスを取得します。user.profile
属性を使って、Profile
クラスのインスタンスを取得します。session.close
メソッドを使って、セッションを閉じます。
このコードを実行すると、example.db
データベースにusers
テーブルとprofiles
テーブルが作成され、John Doe
というユーザーとプロフィール情報が登録されます。
実行結果
# テーブルの作成
CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE profiles (
id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
# ユーザーとプロフィールの登録
INSERT INTO users (name) VALUES ('John Doe');
INSERT INTO profiles (user_id) VALUES (1);
# ユーザー情報の取得
SELECT * FROM users WHERE name='John Doe';
# プロフィール情報の取得
SELECT * FROM profiles WHERE user_id=1;
SQLAlchemyで1対1リレーションシップを作成する他の方法
外部キー制約とForeignKey
アノテーション
代わりに、Column
アノテーションのforeign_keys
引数を使って外部キー制約を定義することもできます。
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'))
user = relationship(User, back_populates='profile')
# 関係を定義
User.profile = relationship(Profile, uselist=False, back_populates='user')
Column
アノテーションのforeign_keys
引数に、参照先のテーブルと列名を指定することで、外部キー制約を定義できます。
ondelete
オプションを指定することで、参照先レコードが削除されたときの挙動を指定できます。
foreign_keys
引数とrelationship
アノテーション
foreign_keys
引数とrelationship
アノテーションを組み合わせて、外部キー制約とリレーションシップを同時に定義することもできます。
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship(User, foreign_keys=[user_id], back_populates='profile')
# 関係を定義
User.profile = relationship(Profile, uselist=False, back_populates='user')
relationship
アノテーションのforeign_keys
引数に、外部キー制約の列名を指定することで、外部キー制約とリレーションシップを同時に定義できます。
上記の3つの方法はいずれも、SQLAlchemyで1対1リレーションシップを作成するために使用できます。
どの方法を使用しても、同じ結果が得られます。
sqlalchemy