Flask + SQLAlchemyで音楽共有SNSを作る - ユーザープロフィールページ編

## はじめに

前回の記事では、フォロー/アンフォロー機能の実装について解説しました。今回は、ユーザープロフィールページの実装について詳しく説明します。このページでは、特定のユーザーの情報と投稿を表示します。

## ユーザープロフィールページの実装

以下に、ユーザープロフィールページを表示する機能の実装コードを示します：

```python
from flask import render_template
from flask_login import login_required
from app import app
from app.models import User, DailySong

@app.route('/user/<username>')
@login_required
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    posts = DailySong.query.filter_by(user_id=user.id).order_by(
        DailySong.date_posted.desc()).all()
    return render_template('user.html', user=user, posts=posts)
```

## 機能の詳細解説

1. **ルーティングとアクセス制御**
   ```python
   @app.route('/user/<username>')
   @login_required
   ```
   - `<username>`は動的なURLパラメータで、アクセスされたユーザー名を取得します。
   - `@login_required`デコレータにより、ログインしているユーザーのみがアクセスできます。

2. **ユーザーの取得**
   ```python
   user = User.query.filter_by(username=username).first_or_404()
   ```
   - 指定されたユーザー名でデータベースを検索します。
   - `first_or_404()`メソッドを使用することで、ユーザーが存在しない場合は自動的に404エラーを返します。

3. **ユーザーの投稿の取得**
   ```python
   posts = DailySong.query.filter_by(user_id=user.id).order_by(
       DailySong.date_posted.desc()).all()
   ```
   - ユーザーIDに基づいて、そのユーザーの全ての投稿を取得します。
   - `order_by(DailySong.date_posted.desc())`で投稿を日付の降順（最新のものから）にソートします。

4. **テンプレートのレンダリング**
   ```python
   return render_template('user.html', user=user, posts=posts)
   ```
   - `user.html`テンプレートをレンダリングし、ユーザー情報と投稿データを渡します。

## テンプレートの例

`user.html`テンプレートの例を以下に示します：

```html
{% extends "base.html" %}

{% block content %}
    <h1>{{ user.username }}のプロフィール</h1>
    
    {% if user.favorite_band %}
        <p>好きなバンド: {{ user.favorite_band }}</p>
    {% endif %}
    
    {% if user.favorite_genre %}
        <p>好きなジャンル: {{ user.favorite_genre }}</p>
    {% endif %}
    
    {% if user != current_user %}
        {% if current_user.is_following(user) %}
            <a href="{{ url_for('unfollow', username=user.username) }}" class="btn btn-secondary">フォロー解除</a>
        {% else %}
            <a href="{{ url_for('follow', username=user.username) }}" class="btn btn-primary">フォローする</a>
        {% endif %}
    {% endif %}
    
    <h2>投稿した楽曲</h2>
    {% for post in posts %}
        <div class="post">
            <h3>{{ post.title }} - {{ post.artist }}</h3>
            <p>ジャンル: {{ post.genre }}</p>
            <p>投稿日: {{ post.date_posted.strftime('%Y-%m-%d') }}</p>
            <a href="{{ post.music_url }}" target="_blank">曲を聴く</a>
        </div>
    {% else %}
        <p>まだ投稿がありません。</p>
    {% endfor %}
{% endblock %}
```

## 機能の特徴とユーザビリティ

1. **プロフィール情報の表示**: ユーザー名、好きなバンド、好きなジャンルなどの基本情報を表示します。

2. **フォロー/アンフォロー機能の統合**: 他のユーザーのプロフィールページを見ている場合、フォロー/アンフォローボタンを表示します。

3. **投稿の一覧表示**: ユーザーが投稿した楽曲を新しい順に表示します。

4. **外部リンク**: 各投稿に「曲を聴く」リンクを設置し、ユーザーが簡単に楽曲にアクセスできるようにしています。

5. **条件付き表示**: 投稿がない場合は適切なメッセージを表示します。

## セキュリティとプライバシーの考慮点

1. **アクセス制御**: `@login_required`デコレータにより、ログインユーザーのみがプロフィールページにアクセスできます。

2. **エラーハンドリング**: 存在しないユーザー名でアクセスした場合、`first_or_404()`メソッドにより適切に404エラーを返します。

3. **プライバシー設定**: 現在の実装では全ての情報が公開されていますが、ユーザーが公開/非公開を設定できる機能を追加することも検討できます。

## 今後の改善案

1. **ページネーション**: 投稿数が多い場合、ページネーション機能を追加して表示を最適化します。

2. **プロフィール編集機能**: ユーザーが自分のプロフィール情報を編集できる機能を追加します。

3. **統計情報の表示**: 投稿数、フォロワー数、フォロー中のユーザー数などの統計情報を表示します。

4. **アクティビティフィード**: ユーザーの最近のアクティビティ（フォロー、いいねなど）を表示します。

## まとめ

ユーザープロフィールページの実装により、ユーザー間のつながりを視覚化し、各ユーザーの音楽の好みや投稿履歴を簡単に確認できるようになりました。これにより、ユーザー同士の交流が促進され、アプリケーションのソーシャル機能が強化されます。

## 参考リンク
- [Flask ルーティング](https://flask.palletsprojects.com/en/2.0.x/quickstart/#routing)
- [SQLAlchemy クエリAPI](https://docs.sqlalchemy.org/en/14/orm/query.html)
- [Jinja2 テンプレート言語](https://jinja.palletsprojects.com/en/3.0.x/templates/)