Flask + SQLAlchemyで音楽共有SNSを作る - ユーザーモデル編

## はじめに

前回の記事では、データベースの初期化とマイグレーションの設定について解説しました。今回は、アプリケーションの中心となるユーザーモデルの定義について詳しく説明します。

## ユーザーモデルの定義

ユーザーモデルは、アプリケーションのユーザー情報を表現し、データベースに保存するための設計図です。以下にユーザーモデルの完全な定義を示します：

```python
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)
    favorite_band = db.Column(db.String(120))
    favorite_genre = db.Column(db.String(50))
    icon = db.Column(db.String(120))

    followed = db.relationship(
        'User', secondary=followers,
        primaryjoin=(followers.c.follower_id == id),
        secondaryjoin=(followers.c.followed_id == id),
        backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')

    def follow(self, user):
        if not self.is_following(user):
            self.followed.append(user)

    def unfollow(self, user):
        if self.is_following(user):
            self.followed.remove(user)

    def is_following(self, user):
        return self.followed.filter(
            followers.c.followed_id == user.id).count() > 0
```

## ユーザーモデルの詳細解説

### 基本属性

1. **id**: ユーザーの一意の識別子。主キーとして使用されます。
   ```python
   id = db.Column(db.Integer, primary_key=True)
   ```

2. **username**: ユーザー名。一意であり、必須項目です。
   ```python
   username = db.Column(db.String(80), unique=True, nullable=False)
   ```

3. **password**: パスワード。必須項目です。実際の実装では、このパスワードをハッシュ化して保存します。
   ```python
   password = db.Column(db.String(120), nullable=False)
   ```

4. **favorite_band**: ユーザーのお気に入りバンド。
   ```python
   favorite_band = db.Column(db.String(120))
   ```

5. **favorite_genre**: ユーザーのお気に入り音楽ジャンル。
   ```python
   favorite_genre = db.Column(db.String(50))
   ```

6. **icon**: ユーザーアイコンのファイルパス。
   ```python
   icon = db.Column(db.String(120))
   ```

### フォロー関係の定義

```python
followed = db.relationship(
    'User', secondary=followers,
    primaryjoin=(followers.c.follower_id == id),
    secondaryjoin=(followers.c.followed_id == id),
    backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')
```

- この関係定義により、ユーザー間のフォロー/フォロワーの関係を表現しています。
- `secondary=followers`: 中間テーブル（前回定義した`followers`テーブル）を指定します。
- `primaryjoin`と`secondaryjoin`: フォロワーとフォロー対象のユーザーを関連付けるための条件を指定します。
- `backref`: 逆方向の関係（フォロワー）を定義します。
- `lazy='dynamic'`: クエリをその場で実行せず、必要なときに評価するように設定します。

### フォロー関連のメソッド

1. **follow**: ユーザーをフォローするメソッド
   ```python
   def follow(self, user):
       if not self.is_following(user):
           self.followed.append(user)
   ```

2. **unfollow**: フォローを解除するメソッド
   ```python
   def unfollow(self, user):
       if self.is_following(user):
           self.followed.remove(user)
   ```

3. **is_following**: フォローしているかチェックするメソッド
   ```python
   def is_following(self, user):
       return self.followed.filter(
           followers.c.followed_id == user.id).count() > 0
   ```

## まとめ

このユーザーモデルの定義により、以下のことが可能になります：

1. ユーザー情報のデータベースへの保存と取得
2. ユーザー間のフォロー関係の管理
3. ユーザーの音楽プレファレンス（お気に入りバンド、ジャンル）の保存

## 参考リンク
- [SQLAlchemy ORM](https://docs.sqlalchemy.org/en/14/orm/)
- [Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/)
- [Flask-Login](https://flask-login.readthedocs.io/)