SQLAlchemyで双方向の友情関係を構築する際のサンプルコード

2024-05-20

SQLAlchemy を用いた双方向の友情関係の構築

モデルの作成

まず、UserFriendship という2つのモデルを作成します。

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

class Friendship(Base):
    __tablename__ = 'friendships'
    id = Column(Integer, primary_key=True)
    user_id1 = Column(Integer, ForeignKey('users.id'))
    user_id2 = Column(Integer, ForeignKey('users.id'))

    user1 = relationship('User', foreign_keys=[user_id1])
    user2 = relationship('User', foreign_keys=[user_id2])

User モデルには、idname という属性があります。Friendship モデルには、iduser_id1user_id2 という属性があります。user_id1user_id2 は、それぞれ User モデルの id を参照する外部キーです。

関係の定義

次に、user1user2 属性を使用して、UserFriendship モデル間の関係を定義します。

user1 = relationship('User', foreign_keys=[Friendship.user_id1])
user2 = relationship('User', foreign_keys=[Friendship.user_id2])

user1 属性は、Friendship レコードに関連付けられている User レコードを返します。user2 属性は、Friendship レコードに関連付けられている別の User レコードを返します。

友情関係の作成

User レコードと Friendship レコードを作成して、2人のユーザー間の友情関係を表現できます。

user1 = User(name='Alice')
user2 = User(name='Bob')

friendship = Friendship(user_id1=user1.id, user_id2=user2.id)

session.add(user1)
session.add(user2)
session.add(friendship)
session.commit()

このコードは、AliceBob の間の友情関係を作成します。

user1 属性と user2 属性を使用して、Friendship レコードに関連付けられている User レコードを取得できます。

friendship = session.query(Friendship).filter(Friendship.id == 1).first()

print(friendship.user1.name)  # Alice
print(friendship.user2.name)  # Bob

このコードは、id が 1 の Friendship レコードを取得し、それに関連付けられている User レコードの名前を出力します。

friendship = session.query(Friendship).filter(Friendship.id == 1).first()

session.delete(friendship)
session.commit()

このコードは、id が 1 の Friendship レコードを削除します。

双方向の友情関係を構築すると、以下の利点があります。

  • どちらのユーザーからも友情関係を確認できます。

その他の考慮事項

  • 友情関係は対称的である必要があります。つまり、user1user2 の友達である場合、user2user1 の友達である必要があります。
  • 友情関係は排他的である必要があります。つまり、ユーザーは同じ人と複数の友情関係を持つことはできません。

SQLAlchemy を用いて双方向の友情関係を構築することは、比較的簡単です。この方法を使用すると、ユーザー間の友情関係を効率的に管理できます。




SQLAlchemy を用いた双方向の友情関係のサンプルコード

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship

engine = create_engine('sqlite:///friends.db')
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

class Friendship(Base):
    __tablename__ = 'friendships'
    id = Column(Integer, primary_key=True)
    user_id1 = Column(Integer, ForeignKey('users.id'))
    user_id2 = Column(Integer, ForeignKey('users.id'))

    user1 = relationship('User', foreign_keys=[user_id1])
    user2 = relationship('User', foreign_keys=[user_id2])

Base.metadata.create_all(engine)

# 友情関係の作成
user1 = User(name='Alice')
user2 = User(name='Bob')

friendship = Friendship(user_id1=user1.id, user_id2=user2.id)

session.add(user1)
session.add(user2)
session.add(friendship)
session.commit()

# 友情関係の取得
friendship = session.query(Friendship).filter(Friendship.id == 1).first()

print(friendship.user1.name)  # Alice
print(friendship.user2.name)  # Bob

# 友情関係の削除
friendship = session.query(Friendship).filter(Friendship.id == 1).first()

session.delete(friendship)
session.commit()

このコードは以下のことを実行します。

  1. friends.db という名前の SQLite データベースに接続します。

このサンプルコードは、双方向の友情関係を構築するための基本的な方法を示しています。実際のアプリケーションでは、このコードを拡張して、追加の機能を追加する必要があります。




SQLAlchemy を用いた双方向の友情関係の構築:別の方法

backref 属性を使用すると、関係の両側で反対側の方向を定義できます。

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

    friends = relationship('Friendship', backref='user1')

class Friendship(Base):
    __tablename__ = 'friendships'
    id = Column(Integer, primary_key=True)
    user_id1 = Column(Integer, ForeignKey('users.id'))
    user_id2 = Column(Integer, ForeignKey('users.id'))

    user1 = relationship('User', backref='friends')
    user2 = relationship('User')

このコードは、以下の点で前述のコードとは異なります。

  • User モデルの friends 属性は、Friendship レコードのリストを返します。
  • Friendship モデルの user2 属性には backref 属性が指定されています。これは、Friendship レコードに関連付けられている User レコードを取得するために user2 属性を使用できることを意味します。

secondary テーブルを使用すると、多くの対一の関係を表現できます。

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, Table

engine = create_engine('sqlite:///friends.db')
Base = declarative_base()

association_table = Table('friendships', Base.metadata,
                          Column('user_id1', Integer, ForeignKey('users.id')),
                          Column('user_id2', Integer, ForeignKey('users.id')))

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(255))

    friends = relationship('User', secondary=association_table,
                           primary_key=True,
                           backref='friends')

class Friendship(Base):
    # Friendship モデルは不要

Base.metadata.create_all(engine)

# 友情関係の作成
user1 = User(name='Alice')
user2 = User(name='Bob')

user1.friends.append(user2)
session.add(user1)
session.add(user2)
session.commit()

# 友情関係の取得
friendship = session.query(association_table).filter(association_table.c.user_id1 == user1.id,
                                                   association_table.c.user_id2 == user2.id).first()

print(friendship.user_id1)  # 1
print(friendship.user_id2)  # 2

# 友情関係の削除
friendship = session.query(association_table).filter(association_table.c.user_id1 == user1.id,
                                                   association_table.c.user_id2 == user2.id).first()

session.delete(friendship)
session.commit()
  • Friendship モデルは不要になりました。
  • association_table という名前の Table オブジェクトが作成されました。このテーブルには、user_id1user_id2 という2つの列があります。
  • User モデルの friends 属性は、secondary 引数を使用して association_table テーブルに関連付けられています。

flask-sqlalchemy は、Flask アプリケーションで SQLAlchemy を使用するのを容易にする拡張機能です。

from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///friends.db'
db = SQLAlchemy(app)

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))

    friends = db.relationship('User', secondary='friendships',
                           primary_key=True,
                           backref='friends

sqlalchemy