Flask + SQLAlchemyで音楽共有SNSを作る - 日々の楽曲投稿機能編

## はじめに

前回の記事では、ユーザー固有の機能（マイページ、ログアウト、ファイルアップロード）について解説しました。今回は、このアプリケーションの核心機能である日々の楽曲投稿機能の実装について詳しく説明します。

## 日々の楽曲投稿機能の実装

以下に、日々の楽曲を投稿する機能の実装コードを示します：

```python
from flask import render_template, flash, redirect, url_for
from flask_login import login_required, current_user
from datetime import date
from app import app, db
from app.models import DailySong
from app.forms import DailySongForm

@app.route('/post_daily_song', methods=['GET', 'POST'])
@login_required
def post_daily_song():
    form = DailySongForm()
    if form.validate_on_submit():
        today = date.today()
        DailySong.query.filter_by(
            user_id=current_user.id, date_posted=today, is_current=True).update({'is_current': False})
        new_song = DailySong(
            user_id=current_user.id,
            title=form.title.data,
            artist=form.artist.data,
            genre=form.genre.data,
            music_url=form.music_url.data,
            is_current=True
        )
        db.session.add(new_song)
        db.session.commit()
        flash('今日の1曲を投稿しました！', 'success')
        return redirect(url_for('mypage'))
    return render_template('post_daily_song.html', form=form)
```

## 機能の詳細解説

1. **ルーティングとアクセス制御**
   ```python
   @app.route('/post_daily_song', methods=['GET', 'POST'])
   @login_required
   ```
   - `@login_required`デコレータにより、ログインしているユーザーのみがこの機能にアクセスできます。
   - GETリクエストでフォームを表示し、POSTリクエストで投稿を処理します。

2. **フォームの作成と検証**
   ```python
   form = DailySongForm()
   if form.validate_on_submit():
   ```
   - `DailySongForm`インスタンスを作成します。
   - `validate_on_submit()`メソッドで、フォームが送信され、かつすべてのバリデーションに通過したかを確認します。

3. **既存の投稿の更新**
   ```python
   today = date.today()
   DailySong.query.filter_by(
       user_id=current_user.id, date_posted=today, is_current=True).update({'is_current': False})
   ```
   - 同じ日に既に投稿があれば、それを非アクティブ（`is_current=False`）にします。
   - これにより、1日1曲の制限を実装しています。

4. **新しい投稿の作成**
   ```python
   new_song = DailySong(
       user_id=current_user.id,
       title=form.title.data,
       artist=form.artist.data,
       genre=form.genre.data,
       music_url=form.music_url.data,
       is_current=True
   )
   ```
   - フォームから取得したデータを使用して、新しい`DailySong`オブジェクトを作成します。
   - `is_current=True`を設定し、これを現在のアクティブな投稿としています。

5. **データベースへの保存**
   ```python
   db.session.add(new_song)
   db.session.commit()
   ```
   - 新しい投稿をデータベースセッションに追加し、変更を確定します。

6. **フィードバックとリダイレクト**
   ```python
   flash('今日の1曲を投稿しました！', 'success')
   return redirect(url_for('mypage'))
   ```
   - 成功メッセージをフラッシュし、ユーザーにフィードバックを提供します。
   - 投稿後、ユーザーをマイページにリダイレクトします。

7. **フォーム表示**
   ```python
   return render_template('post_daily_song.html', form=form)
   ```
   - GETリクエスト時、または検証エラー時に、フォームを表示するテンプレートをレンダリングします。

## セキュリティとユーザビリティの考慮点

1. **アクセス制御**: `@login_required`デコレータにより、認証されたユーザーのみが投稿できます。

2. **データ検証**: `DailySongForm`のバリデーションにより、不正なデータの投稿を防ぎます。

3. **重複投稿の防止**: 同じ日の既存の投稿を非アクティブにすることで、1日1曲の制限を実装しています。

4. **ユーザーフィードバック**: `flash`メッセージにより、操作の結果をユーザーに明確に伝えています。

5. **UX考慮**: 投稿後にマイページにリダイレクトすることで、ユーザーは自分の投稿をすぐに確認できます。

## まとめ

この日々の楽曲投稿機能は、アプリケーションの中心的な機能の一つです。ユーザーが毎日1曲を共有できるようにすることで、継続的なエンゲージメントを促進し、ユーザー間の音楽を通じたコミュニケーションを活性化させることができます。

実装にあたっては、セキュリティ、データの整合性、そしてユーザビリティに配慮しています。これにより、安全で使いやすい機能を提供しています。

## 参考リンク
- [Flask-WTF ドキュメント](https://flask-wtf.readthedocs.io/)
- [SQLAlchemy クエリ API](https://docs.sqlalchemy.org/en/14/orm/query.html)
- [Flask フラッシュメッセージ](https://flask.palletsprojects.com/en/2.0.x/patterns/flashing/)