Django のフォームでユーザー入力を受け取る

Web アプリケーションではユーザーからの入力を受け取る場面が必ず発生します。Django のフォーム機能を使えば、HTML フォームの生成・入力値の検証・エラーメッセージの表示を一貫した仕組みで扱えます。

フォームクラスの定義

Django のフォームは forms.py にクラスとして定義します。django.forms.Form を継承し、フィールドをクラス属性として宣言します。

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100, label='お名前')
    email = forms.EmailField(label='メールアドレス')
    message = forms.CharField(widget=forms.Textarea, label='メッセージ')

各フィールドは入力値の型チェックを自動で行います。EmailField であればメールアドレスの形式かどうか、CharField であれば max_length を超えていないかといった基本的なバリデーションが組み込まれています。

よく使うフィールド型を確認しておきましょう。

フィールド型用途HTML の出力
CharField短いテキストinput type="text"
EmailFieldメールアドレスinput type="email"
IntegerField整数input type="number"
フィールド型用途HTML の出力
BooleanFieldチェックボックスinput type="checkbox"
ChoiceFieldセレクトボックスselect
DateField日付input type="text"

widget パラメータを指定すると、HTML の出力形式を変更できます。forms.Textarea を指定すれば <textarea> タグが出力されます。

ビューでフォームを処理する

フォームの処理はビューで行います。GET リクエストで空のフォームを表示し、POST リクエストで送信データを受け取るのが基本パターンです。

from django.shortcuts import render, redirect
from .forms import ContactForm

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            # バリデーション通過後の処理
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            message = form.cleaned_data['message']
            # メール送信などの処理...
            return redirect('contact_done')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})

form.is_valid() を呼び出すと、すべてのフィールドに対してバリデーションが実行されます。検証を通過したデータは form.cleaned_data という辞書に格納され、Python の型に変換された安全な値として取り出せます。

GET: 空のフォームを表示

POST: 送信データでフォームを構築

is_valid() でバリデーション実行

成功ならリダイレクト、失敗なら再表示

テンプレートでフォームを表示する

テンプレートでは、フォームオブジェクトをそのまま出力するだけで HTML が生成されます。

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">送信</button>
</form>

{% csrf_token %} は CSRF 攻撃を防ぐためのトークンで、POST フォームには必ず含めます。これがないと Django は 403 エラーを返します。

フォームの出力方法は複数あります。

form.as_p

各フィールドを p タグで囲んで出力する。手軽だがカスタマイズ性は低い

フィールド個別出力

各フィールドを個別にレンダリングする。レイアウトを自由に制御できる

フィールドを個別に出力する方法も見ておきましょう。

<form method="post">
    {% csrf_token %}
    <div>
        <label for="{{ form.name.id_for_label }}">{{ form.name.label }}</label>
        {{ form.name }}
        {{ form.name.errors }}
    </div>
    <div>
        <label for="{{ form.email.id_for_label }}">{{ form.email.label }}</label>
        {{ form.email }}
        {{ form.email.errors }}
    </div>
    <div>
        <label for="{{ form.message.id_for_label }}">{{ form.message.label }}</label>
        {{ form.message }}
        {{ form.message.errors }}
    </div>
    <button type="submit">送信</button>
</form>

{{ form.name }} でフィールドの HTML を出力し、{{ form.name.errors }} でそのフィールドのエラーメッセージを表示します。実際のプロジェクトではこちらの書き方が圧倒的に多く使われます。CSS フレームワークとの組み合わせやレイアウトの調整が柔軟にできるためです。

初期値を設定する

フォームに初期値を持たせたい場合は initial パラメータを使います。

def contact(request):
    form = ContactForm(initial={
        'name': 'ゲスト',
        'email': 'guest@example.com'
    })
    return render(request, 'contact.html', {'form': form})

initial はフォームの表示時に入力欄にあらかじめ値を入れておくもので、バリデーションには影響しません。編集画面で既存データを表示する場面や、デフォルト値を提示したいときに活用できます。

required と必須チェック

Django のフォームフィールドはデフォルトで必須入力です。任意入力にしたい場合は required=False を指定します。

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100, label='お名前')
    email = forms.EmailField(label='メールアドレス')
    phone = forms.CharField(max_length=20, label='電話番号', required=False)
    message = forms.CharField(widget=forms.Textarea, label='メッセージ')

required=False のフィールドは空欄のまま送信してもバリデーションエラーになりません。cleaned_data には空文字 '' が入ります。

Django のフォーム機能は「HTML の生成」「バリデーション」「安全なデータの取り出し」をまとめて面倒を見てくれる仕組みです。生の request.POST を直接触るよりも安全で、コードの見通しもよくなります。