はじめに

 以下のようなフォームがある。

form1.png

forms.py
from django import forms

class ProfileForm(forms.Form):

    name = forms.CharField()
    age = forms.IntegerField()

template
<form action="{% url 'index' %}" method="POST">
    {% csrf_token %}
    {{ profile_form }}
    <input type="submit" value="送信">
</form>

 これを改造していく。

フィールドを参照する

 テンプレート内でフォームのフィールド名を参照すると対応するフィールドが取り出せる。

forms.py
from django import forms

class ProfileForm(forms.Form):

    name = forms.CharField()
    age = forms.IntegerField()

template
{% with profile_form as f %}
<form action="{% url 'index' %}" method="POST">
    {% csrf_token %}
    <div>{{ f.name }}</div>
    <div>{{ f.age }}</div>
    <input type="submit" value="送信">
</form>
{% endwith %}

 しかしインプット要素のみの取り出しなので味気がない出力になる。

ラベルを参照する

 ラベル名を参照するにはフィールドのlabelを参照する。ちなみにlabel名の参照ではHTMLlabelは生成されないので、別途タグで囲む必要がある。

template
{% with profile_form as f %}
<form action="{% url 'index' %}" method="POST">
    {% csrf_token %}
    <div><label>{{ f.name.label }}</label>: {{ f.name }}</div>
    <div><label>{{ f.age.label }}</label>: {{ f.age }}</div>
    <input type="submit" value="送信">
</form>
{% endwith %}

ラベル名を変更するにはフォームのフィールドのlabelを指定する。

forms.py
from django import forms

class ProfileForm(forms.Form):

    name = forms.CharField(label='名前')
    age = forms.IntegerField(label='年齢')

 出力結果。

form2.png

ヘルプの参照

 フォームのフィールドにhelp_textを設定した場合、テンプレートではフィールドのhelp_textから設定文字列を参照できる。値の検証範囲を入力するのがデフォっぽい。

forms.py
from django import forms

class ProfileForm(forms.Form):

    name = forms.CharField(label='名前', help_text='英字のみ')
    age = forms.IntegerField(label='年齢', help_text='0以上120以下')

template
{% with profile_form as f %}
<form action="{% url 'index' %}" method="POST">
    {% csrf_token %}
    <div>
        <label>{{ f.name.label }}</label>:
        {{ f.name }}
        <p>{{ f.name.help_text }}</p>
    </div>
    <div>
        <label>{{ f.age.label }}</label>:
        {{ f.age }}
        <p>{{ f.age.help_text }}</p>
    </div>
    <input type="submit" value="送信">
</form>
{% endwith %}

 出力結果。

form3.png

フィールドのエラーの参照

 フォームのフィールドは検証に失敗するとエラー文字列をフォームに格納する。テンプレートではフィールドのerrorsから参照できる。

template
{% with profile_form as f %}
<form action="{% url 'index' %}" method="POST">
    {% csrf_token %}
    <div>
        <label>{{ f.name.label }}</label>:
        {{ f.name }}
        <p>{{ f.name.help_text }}</p>
        <p>{{ f.name.errors }}</p>
    </div>
    <div>
        <label>{{ f.age.label }}</label>:
        {{ f.age }}
        <p>{{ f.age.help_text }}</p>
        <p>{{ f.age.errors }}</p>
    </div>
    <input type="submit" value="送信">
</form>
{% endwith %}

バリデーションの追加

 バリデーションを追加するにはフォームにclean_で始まるメソッドを定義する(参照: http://python.keicode.com/django/form-validation.php)。
 デフォルトのバリデーターが呼ばれた後に実行されるらしい。

forms.py
from django import forms

class ProfileForm(forms.Form):

    name = forms.CharField(max_length=20, label='名前', help_text='英字のみ')
    age = forms.IntegerField(label='年齢', help_text='0以上120以下')

    def clean_name(self):
        name = self.cleaned_data['name']

        isallalpha = True
        for c in name:
            if not c.isalpha():
                isallalpha = False
                break

        if not isallalpha:
            raise forms.ValidationError('英字以外が含まれています。')

        return name

    def clean_age(self):
        """
        ちなみにフィールドの属性 min_value, max_valueで入力範囲を制限できる。
        それらを設定したらこのバリデーションは不要?
        """
        age = self.cleaned_data['age']

        if age < 0 or age > 120:
            raise forms.ValidationError('範囲外です。')

        return age

 フォームに不正な値を入力してみた出力結果。

forms4.png

 ちなみにテンプレートでerrorsを参照したい場合、views.pyでちょっとした工夫が必要になる。is_validを呼んだ後のフォームを再度出力用のテンプレートに渡すとerrorsを参照できるようになる。

views.py
from django.shortcuts import render
from django.http import HttpResponse
from . import forms

def index(req):
    if req.method == 'GET':
        return render(req, 'myapp/profile-form.html', {
            'profile_form': forms.ProfileForm(),
        })
    elif req.method == 'POST':
        profile_form = forms.ProfileForm(req.POST)
        if not profile_form.is_valid():
            # ここでerrorsを生かしたままテンプレートに渡す。
            return render(req, 'myapp/profile-form.html', {
                'profile_form': profile_form,
            })

        return HttpResponse('ok')

プレースホルダーの設定

 インプット要素のプレースホルダーはフォームのwidgetで設定できる。widgetの種類は https://github.com/django/django/blob/master/django/forms/widgets.py を参照。

class ProfileForm(forms.Form):

    name = forms.CharField(max_length=20, label='名前', help_text='英字のみ', widget=forms.TextInput(attrs={
        'placeholder': 'Name',
    }))
    age = forms.IntegerField(min_value=0, max_value=120, label='年齢', help_text='0以上120以下', widget=forms.NumberInput(attrs={
        'placeholder': '0',
    }))

 出力結果。

form5.png

 だいぶフォームらしくなりました(・∀・)ノ

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.