Flask + SQLAlchemyで音楽共有SNSを作る - 日々の楽曲投稿フォーム編

## はじめに

前回の記事では、DailySongモデルの定義について解説しました。今回は、ユーザーが日々の楽曲を投稿するためのフォーム、DailySongFormの定義について詳しく説明します。

## DailySongFormの定義

DailySongFormは、Flask-WTFを使用して定義されたフォームクラスで、ユーザーが楽曲情報を入力するためのインターフェースを提供します。以下にDailySongFormの完全な定義を示します：

```python
from flask_wtf import FlaskForm
from wtforms import StringField, SelectField, SubmitField, URLField
from wtforms.validators import DataRequired, URL

class DailySongForm(FlaskForm):
    title = StringField('曲のタイトル', validators=[DataRequired()])
    artist = StringField('アーティスト名', validators=[DataRequired()])
    genre = SelectField('ジャンル', choices=[
        ('pop', 'J-POP'),
        ('rock', 'K-POP'),
        ('jazz', 'ヒップホップ/ラップ'),
        ('classical', 'ロック'),
        ('hiphop', 'ジャズ'),
        ('electronic', 'クラシック'),
        ('other', 'その他')
    ], validators=[DataRequired()])
    music_url = URLField('音楽の共有URL', validators=[DataRequired(), URL()])
    submit = SubmitField('投稿')
```

## DailySongFormの詳細解説

### フォームフィールド

1. **title**: 曲のタイトル入力フィールド
   ```python
   title = StringField('曲のタイトル', validators=[DataRequired()])
   ```
   - `StringField`: テキスト入力フィールドを作成
   - `DataRequired()`: 必須入力を指定

2. **artist**: アーティスト名入力フィールド
   ```python
   artist = StringField('アーティスト名', validators=[DataRequired()])
   ```
   - `StringField`: テキスト入力フィールドを作成
   - `DataRequired()`: 必須入力を指定

3. **genre**: ジャンル選択フィールド
   ```python
   genre = SelectField('ジャンル', choices=[
       ('pop', 'J-POP'),
       ('rock', 'K-POP'),
       ('jazz', 'ヒップホップ/ラップ'),
       ('classical', 'ロック'),
       ('hiphop', 'ジャズ'),
       ('electronic', 'クラシック'),
       ('other', 'その他')
   ], validators=[DataRequired()])
   ```
   - `SelectField`: ドロップダウンリストを作成
   - `choices`: 選択肢のリストを指定（値, 表示テキスト）
   - `DataRequired()`: 必須選択を指定

4. **music_url**: 音楽URLの入力フィールド
   ```python
   music_url = URLField('音楽の共有URL', validators=[DataRequired(), URL()])
   ```
   - `URLField`: URL入力用のフィールドを作成
   - `DataRequired()`: 必須入力を指定
   - `URL()`: 有効なURLであることを検証

5. **submit**: 投稿ボタン
   ```python
   submit = SubmitField('投稿')
   ```
   - `SubmitField`: フォーム送信ボタンを作成

### バリデーション

- `DataRequired()`: 全てのフィールドで使用され、空の入力を防ぎます。
- `URL()`: `music_url`フィールドで使用され、有効なURLであることを確認します。

## DailySongFormの特徴と利点

1. **ユーザーフレンドリーなインターフェース**: 各フィールドにラベルが付いており、ユーザーが何を入力すべきか明確です。

2. **入力検証**: バリデータにより、サーバーサイドで入力データの妥当性を確認できます。

3. **ジャンルの標準化**: `SelectField`を使用することで、ジャンルの選択肢を統一し、データの一貫性を保つことができます。

4. **柔軟性**: 必要に応じて、新しいフィールドの追加や既存のフィールドの修正が容易です。

5. **セキュリティ**: Flask-WTFは自動的にCSRF保護を提供し、クロスサイトリクエストフォージェリ攻撃を防ぎます。

## 使用例

ビュー関数でこのフォームを使用する例：

```python
@app.route('/post_song', methods=['GET', 'POST'])
@login_required
def post_song():
    form = DailySongForm()
    if form.validate_on_submit():
        song = DailySong(
            title=form.title.data,
            artist=form.artist.data,
            genre=form.genre.data,
            music_url=form.music_url.data,
            user=current_user
        )
        db.session.add(song)
        db.session.commit()
        flash('楽曲が投稿されました！')
        return redirect(url_for('index'))
    return render_template('post_song.html', form=form)
```

## まとめ

DailySongFormの定義により、以下のことが可能になります：

1. ユーザーからの楽曲情報の収集
2. 入力データの検証
3. ジャンルの標準化
4. セキュアなフォーム処理

## 参考リンク
- [Flask-WTF Documentation](https://flask-wtf.readthedocs.io/)
- [WTForms Documentation](https://wtforms.readthedocs.io/)
- [Flask Form Validation with WTForms](https://flask.palletsprojects.com/en/2.0.x/patterns/wtforms/)