Djangoのフォーム機能
Formクラス
Djangoにはフォームをもっとスマートに書くための Formクラスがある。Formクラスは、フォームの内容をPythonのクラスとして定義するもの。Formクラスでフォームの内容を定義し、テンプレートに変数として渡すことで、クラスの内容をもとにフォームが自動生成される。
forms.py
を作る
hello
アプリ直下にforms.py
を用意する。name
,mail
,age
の3つのフィールドを持つ。
from django import forms class HelloForm(forms.Form): name = forms.CharField(label='name') mail = forms.CharField(label='mail') age = forms.IntegerField(label="age")
Formクラスの書き方
Formクラスの書き方は簡単で、必要なフィールドを変数として用意しておくだけ。
class クラス名 (forms.Form): 変数 = フィールド 変数 = フィールド .......
forms.CharField : テキスト入力の一般的なフィールド
forms.IntegerField : 整数値入力のフィールド
書くフィールドにlabel='name'
といった形で渡されるラベルは、フィールド手前に表示されるフィールド名のテキスト。
ビュー関数の作成
作ったFormクラスのHelloForm
を利用するビュー関数をhello/views.py
に作る。
from django.shortcuts import render from django.http import HttpResponse from .forms import HelloForm def index(request): params = { 'title': 'Hello', 'msg': 'your data:', 'form': HelloForm() } if (request.method == 'POST'): params['message'] = '名前: ' + request.POST['name'] + \ '<br/>メール: ' + request.POST['mail'] + \ '<br/>年齢: ' + request.POST['age'] params['form'] = HelloForm(request.POST) return render(request, 'hello/index.html', params)
index関数
内にGETの処理とPOSTの処理を両方書いている。まず共通の処理(パラメータの用意)をし、if (request.method == 'POST'):
でPOST送信であったときのみの処理を書いている。パラメータの定義、
params = {
......
'form': HelloForm()
}
の中でform
というキーの変数にHelloForm
インスタンスを代入し、
POST送信の場合はparams['form'] = HelloForm(request.POST)
で送られてきた値を元に作成したHelloForm
インスタンスを再度キーform
のパラメータに上書きしている。
HelloFormを表示する
hello/templates/hello/index.html
テンプレートを書き換える。
{% load static %} <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{title}}</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous"> </head> <body class="container"> <h1 class="display-4 text-primary">{{title}}</h1> <p class="h5 mt-4">{{message|safe}}</p> <form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form }} <input type="submit" value="click" class="btn btn-primary"> </form> </body> </html>
Formクラスを利用する場合は{{ form }}
でフォームの具体的な内容が書き出されるので、記述が簡素化される。
safe
フィルター
メッセージの表示部分を{{message|safe}}
とし、safe
フィルターを通した表示にすることでエスケープ処理をせずにHTMLタグはタグとして表示する。
urlpatterns
の修正
hello/urls.py
を修正する。
urlpatterns = [ path('', views.index, name='index'), ]
index関数
にGET,POST両方の処理をまとめたので、今度はindex
へのパスだけでよい。
表示結果
http://localhost:8000/hello/
にアクセスしフォーム入力画面に値を入れて送信ボタンをクリックすると、
Hello
入力した値がフォームの上部に表示される。
Hello
名前: Foo
メール: foo@example.com
年齢: 35
何も入力せずにボタンを押すと「!このフィールドを入力して下さい」といった警告が自動的に出る。
フォームフィールドをタグで整理する
Formクラスには、フォームフィールドを整形するための機能がある。
<Form>.as_table
: ラベルとフィールドをtr
タグとtd
タグで囲む
<Form>.as_p
: ラベルとフィールドをp
で囲む
<Form>.as_table
: ラベルとフィールドをli
タグで囲む
<Form>.as_table
を使ってindex.html
テンプレートを修正する。
{% load static %} <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{title}}</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous"> </head> <body class="container"> <h1 class="display-4 text-primary">{{title}}</h1> <p class="h5 mt-4">{{message|safe}}</p> <form action="{% url 'index' %}" method="post"> {% csrf_token %} <table> {{ form.as_table }} <tr> <td></td> <td> <input type="submit" value="click" class="btn btn-primary"> </td> </tr> </table> </form> </body> </html>
table
タグまでは生成してくれないのは一見面倒だが、実際はそこを手で書き入れるからこそ、手書きで挿入した送信ボタンも<table>
の中に入れて整理できた。
Formクラスのwidget
の利用
Formクラスの定義で、引数にwidget
の値を用意すると、生成されるタグにカスタム属性を追加できる。hello/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.TextInput(attrs=属性値)
forms.NumberInput(attrs=属性値)
といった形で指定する。
これに合わせてindex.html
テンプレートも修正する。単純化するために<Form>.as_p
を使う。
<form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="click" class="btn btn-primary my-2"> </form>
出力されたHTMLにはclass
名にform-control
が追加されている。
<p> <label for="id_name">name:</label> <input type="text" name="name" value="Foo" class="form-control" required="" id="id_name"> </p>