Formクラスのモジュール
基本的な使い方
forms.py
での定義
Djangoが用意しているフォーム関連の親クラスを継承して、カスタムフォームクラスの定義をする。Djangoの基本的なフォームクラスはdjango.forms.Form
となっている。
アプリのDIR直下にforms.py
というファイルを作る。例えばdjango_app
プロジェクトのhello
アプリならば、django_app/hello/forms.py
。その先頭でfrom django import forms
としてDjangoの基本的なフォームクラスをインポートし、作りたいカスタムフォームクラスの引数にforms.Form
を渡す。
#forms.py from django import forms class HelloForm(forms.Form): name = forms.CharField(label='name', widget=forms.TextInput(attrs={'class':'form-control'})) mail = forms.CharField(label='mail', widget=forms.TextInput(attrs={'class':'form-control'})) age = forms.IntegerField(label="age", widget=forms.NumberInput(attrs={'class':'form-control'})) ..........
作ったクラスの中で、フィールド変数を変数名 = forms.フィールドクラス(フィールドの引数)
という形で定義する。
フィールド引数
- required: True/False、値はbool型で文字列では無いので注意、またPythonなので先頭大文字
- label: 入力フィールドに付けられるラベルの文字列
- initial: 初期値
- widget: widget を指定する。
- help_text: 文字列
- error_messages: エラーメッセージをディクショナリで渡* す {'required':'Enter your name.'} など
- validators (Django 1.2 以降)
- localize (Django 1.2 以降)
例:「体重」をインプットする実数値の入力フィールドをこのように定義すると、
body_weight = forms.FloatField(label="体重", initial="45", widget=forms.NumberInput(attrs={'class':'body-weight'}))
HTMLはこうなる。
出力されるHTML
<p> <label for="id_body_weight">体重:</label> <input type="number" name="body_weight" value="45" class="body-weight" step="any" required="" id="id_body_weight"> </p>
- 出力タグ
<input type="number">
- ラベル
- 「体重」
- ラベルのID
id_フィールド変数名
- 初期値
- 45
- inputタグの属性
name="フィールド変数名"
,class="body-weight"
,IDがid_フィールド変数名
,required
の属性があるので入力が必須。
widget フィールド引数
フォームフィールドの外見を決めるもので、HTMLタグにクラス名を渡すなどに利用できるが、例えば<input type="number">
などにしたいのにforms.TextInput
といった値にしていたのではそうならないので注意。
widgetの種類とレンダリングされるタグの関係
TextInput : <input type="text" ...>
NumberInput : <input type="number" ...>
EmailInput : <input type="email" ...>
URLInput : <input type="url" ...>
PasswordInput : <input type="password" ...>
HiddenInput : <input type="hidden" ...>
DateInput : <input type="text" ...>
CheckBoxInput : <input type="checkbox" ...>
Select : <select><option ...><select>
views.py
での利用
後はそのフォームを使いたいビューの中で、つまりアプリのviews.py
の中でインポートし、TemplateViewクラスを継承したクラスの中で、初期化時のパラメータに代入したうえでメソッドで利用する。
# views.py from .forms import HelloForm class HelloView(TemplateView): def __init__(self): self.params = { ...... 'form': HelloForm() } .......... def post(self, request): ........ self.params['form'] = HelloForm(request.POST)
テンプレートでの利用
テンプレートの中で{{ form }}
と書いた箇所に自動的にフォームが出力される。この場合forms.py
のカスタムフォームクラスに定義した順番に出力される。実際forms.py
で上記のage = forms.IntegerField(....)
を最初に持ってくると、HTMLでは年齢入力フィールドが先頭になる。
例:hello/templates/hello/index.html
でカスタムフォームクラスのインスタンスを使う。
<form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="click" class="btn btn-primary my-2"> </form>
ビルトインFieldクラス
CharField
文字列のフィールド=テキスト入力のためのクラス。
<input type="text">
を生成する。
EmailField
メールアドレスの入力フィールド。
<input type="email">
を生成。メールアドレス形式では無い文字列を入力すると「Enter a valid email address.」といったエラーメッセージが出る。
IntegerField
整数値の入力フィールド。
<input type="number">
を生成。
対応しているブラウザならば、右端に増減ボタンなどが表示される。整数値以外の入力には「有効な値を入力して下さい」などの警告が出る。
FloatField
実数値も入力できるフィールド。
<input type="number">
を生成。
URLField
URL入力のためのフィールド。
<input type="url">
を生成。入力されたアドレスが実際に存在するかまでのチェックはできないが、URL文字列になっているかのチェックは行う。「Enter a valid URL.」などの警告が出る。
日時に関するフィールド
DateField
日付の入力フィールド。
TimeField
時刻の入力フィールド
DateTimeField
日付と時間の入力フィールド
入力できる日時のフォーマットは制限がある。
-
日時の形式
2020-02-01
02/01/2020
02/01/20 -
時刻の形式
12:34
12:34:45 -
日付と時間:日付と時間をスペース区切りで入力
02/01/2020 12:34
BooleanField
チェックボックスのフィールド
チェックボックスはOFFの場合値が送信されないので、必ずrequired=False
にする。
check = forms.BooleanField(label='CheckBox', required=False)
hello/forms.py
class HelloForm(forms.Form): check = forms.BooleanField(label='CheckBox', required=False)
hello/views.py
class HelloView(TemplateView): def __init__(self): self.params = { 'title': 'Hello', 'form': HelloForm(), 'checked': False, } def get(self, request): return render(request, 'hello/index.html', self.params) def post(self, request): if ('check' in request.POST): self.params['checked'] = True else: self.params['checked'] = False self.params['form'] = HelloForm(request.POST) return render(request, 'hello/index.html', self.params)
hello/templates/hello/index.html
(body部分のみ)
<body class="container"> <h1 class="display-4 text-primary">{{title}}</h1> <p class="h5 mt-4">{{message|safe}}</p> {% if checked %} <p class="h5 mt-4">Checked!</p> {% else %} <p class="h5 mt-4">No check.</p> {% endif %} <form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="click" class="btn btn-primary my-2"> </form> </body>
これでチェックボックスがチェックされていれば「Checked!」、されていなければ「No check.」と表示される。
NullBooleanField
'Yes, No, Unknown'の3択フィールド
hello/forms.py
class HelloForm(forms.Form): check = forms.NullBooleanField(label='Check')
hello/views.py
class HelloView(TemplateView): def __init__(self): self.params = { 'title': 'Hello', 'form': HelloForm(), 'result': None, } def get(self, request): return render(request, 'hello/index.html', self.params) def post(self, request): chk = request.POST['check'] self.params['result'] = f"You selected: '{chk}'." self.params['form'] = HelloForm(request.POST) return render(request, 'hello/index.html', self.params)
hello/templates/hello/index.html
(body部分のみ)
<body class="container"> <h1 class="display-4 text-primary">{{title}}</h1> <p class="h5 mt-4">{{result|safe}}</p> <form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="click" class="btn btn-primary my-2"> </form> </body>
'Yes, No, Unknown'の3択プルダウンメニューが表示され、You selected: '....'
の部分にunknown
、true
、false
のいずれかが表示される(Chromeの場合)。
ChoiceField
プルダウンメニュー(選択のフィールド)。choices
という引数を持ち、それにタプルのリストを渡すとプルダウンメニューが表示される。
hello/forms.py
class HelloForm(forms.Form): data = [ ('one', 'item 1'), ('two', 'item 2'), ('three', 'item 3') ] choice = forms.ChoiceField(label='Choice', choices=data)
hello/views.py
class HelloView(TemplateView): def __init__(self): self.params = { 'title': 'Hello', 'form': HelloForm(), 'result': None, } def get(self, request): return render(request, 'hello/index.html', self.params) def post(self, request): ch = request.POST['choice'] self.params['result'] = f'You selected: "{ch}".' self.params['form'] = HelloForm(request.POST) return render(request, 'hello/index.html', self.params)
hello/templates/hello/index.html
(body部分のみ)
<body class="container"> <h1 class="display-4 text-primary">{{title}}</h1> <p class="h5 mt-4">{{result|safe}}</p> <form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="click" class="btn btn-primary my-2"> </form> </body>
これでhttp://localhost:8000/hello/
にアクセスすると「item 1, item 2, item 3」という項目のプルダウンメニューが表示される。生成されるセレクトメニューのリストは、下記のようにタプルで定義した1番目の値が<option value="one">
などの形でタグの値になり、2番目の値がメニューに表示される文字列になる。
<p> <label for="id_choice">Choice:</label> <select name="choice" id="id_choice"> <option value="one">item 1</option> <option value="two">item 2</option> <option value="three" selected="">item 3</option> </select> </p>
選んだ項目でch = request.POST['choice']
に代入されるのはoption
タグの値=value
になるので、'one','two','three'
という値になる。
ラジオボタン
Djangoにはラジオボタン専用のフィールドクラスは無いので、ChoiceField を使って作成する。
forms..ChoiceField(label='radio', choices=データ, widget=forms.RadioSelect())
hello/forms.py
class HelloForm(forms.Form): data = [ ('one', 'radio 1'), ('two', 'radio 2'), ('three', 'radio 3') ] choice = forms..ChoiceField(label='radio', choices=data, widget=forms.RadioSelect())
widget
にforms.RadioSelect
を与えることで、ChoiceField
を使いながらラジオボタンの表示になる。
他の基本的な仕組みはプルダウンメニューと同じ。
項目選択リスト(一項目選択)
これもやはり一項目選択リスト専用のフィールドクラスは無いので、ChoiceField を使って作成する。
widget
にforms.Select
を与えることで、ChoiceField
を使いながら選択リストの表示になる。
forms..ChoiceField(label='MenuList', choices=データ, widget=forms.Select())
hello/forms.py
class HelloForm(forms.Form): data = [ ('one', 'item 1'), ('two', 'item 2'), ('three', 'item 3'), ('four', 'item 4'), ('five', 'item 5'), ] choice = forms.ChoiceField(label='MenuList', choices=data, widget=forms.Select(attrs={'size':5}))
項目数の属性size="5"
をselectタグに渡すために、forms.Select
にattrs={'size':5}
という引数を与えて表示範囲を決めている。
MultipleChoiceField
複数選択可能な項目選択リストの場合は、MultipleChoiceField
という専用のフィールドクラスがある。
forms.MultipleChoiceField(label='MenuList', choices=データ, widget=forms.SelectMultiple())
複数選択可能なリストの場合は、POSTで送られてくる値もリストになっている。そのためrequest.POST['choice']
といったやり方では無く、request.POST.getlist('choice')
という形でgetlistメソッド
を使う形にhello/views.py
を書き換える必要がある。
getlistメソッド
は送られてきた値をリストとして取り出す。
hello/views.py
class HelloView(TemplateView): def __init__(self): self.params = { 'title': 'Hello', 'form': HelloForm(), 'result': None, } def get(self, request): return render(request, 'hello/index.html', self.params) def post(self, request): ch = request.POST.getlist('choice') self.params['result'] = f'You selected: "{str(ch)}".' self.params['form'] = HelloForm(request.POST) return render(request, 'hello/index.html', self.params)
You selected: "['one', 'three', 'four']".
結果表示もYou selected: "['one', 'three', 'four']".
というふうにリストで表示する形になる。