第四回目Python Djangoフレームワークを使ったフォーム機能を実装。
初心者プログラマー用のwebアプリ作成チュートリアル始めます。前回は画像, CSS, JavaScriptを使う方法でした。
フォームを使えるようになると入力情報してもらうことで一般的なWEBアプリだけでなく、AI、画像認識機械学習、自然言語系の機械学習だろうが入力されたフォームの情報を使って役に立つWebアプリで使えるようになると思います。
Pythonを使っているならぜひ身につけておきたいところですね。
内容が古くなったのでDjango 3で記事更新しました。 updated: 2021/09
Pythonで作るDjangoアプリ記事一覧
内容 | |
---|---|
part1 | 簡単な文字表示アプリを作る |
part2 | HTMLテンプレート表示 |
part3 | "画像" "CSS" "Javascript"実装 |
part4 | フォーム送信 ← ココ |
part5 | データベースの値取得・更新 |
番外編 | Django AWS デプロイ |
APIサーバー編 | Django REST frameworkとReact #4 |
単体テスト編 | Django unittestで単体テスト |
ソースコード
この章のコードは以下です。確認やコピペでどうぞ
Djangoのフォーム機能が便利
Djangoを使うなら便利なform機能を使って作りましょう。
入力エラーのチェックなど実装されていますし、コードも少なく作れます。
Djangoのformって何?
HTMLのformといえば、MDNより文字の入力なら
選択フォームなら
こんな感じです。CSSで装飾されてないので見た目は違うかもしれないですけど、HTMLのformといえばこんなものですね。
DjangoのformはHTMLのformの要素なんかを作ることもできるんですが、Djangoのformで本当に大事なのは次に示すようなことです。
Djangoのformの機能
- 入力(選択)されたデータにエラーがないかチェックできる
- 入力できるデータの型とか形式を定義できる
- エラーメッセージなどを活用できる
- HTMLのform要素から得られたデータだけだとPythonで使うには不便なことあるのでデータの加工するのも任せよう
なんてのが本質的な機能です。
ただ、今回は初歩的な内容を扱うのでフォームを作るくらいにとどめます。すみません。。。
forms.py作成
では、さっそく作っていきましょう!forms.py
ファイルを作成します。
C:\Users\○○○\django\testproject\webtestapp\forms.py
from django import forms
class TestForm(forms.Form):
text = forms.CharField(label='文字入力')
num = forms.IntegerField(label='数量')
forms.Form
クラスを継承してTestForm
というのを作ってみました。
とりあえず難しいことはいいので、forms.Formクラスというのにformのデータチェックとか、データの定義とかするための部品がたくさん入っていると思っておけばいいと思います。
で、部品を使って自分の作りたいデータ入力できる機能を作る定義を追加していくことになります。
定義したのは、
-
forms.CharField
はテキストを入力するフォーム。 -
forms.IntegerField
は数値(整数)入力するフォーム。
labelは表示されたときにフォーム横に表示されるテキスト。HTMLにlabelタグありますね。あれです。
これで、HTMLテンプレートに埋め込んだときにいい感じで判断してくれて、
-
forms.CharField
なら文字入力フォーム -
forms.IntegerField
なら数値を▲ ▼押したら増減できるフォーム
以下からは、前回までの続きなので今回のフォーム送信には関係無いものもありますので適時読み飛ばしや追加などしてください。
views.pyに記述
では、最初にformがどんな感じか見るために画面に表示させてみましょう。
from django.shortcuts import render
from .forms import TestForm # 追加
def index(request):
my_dict = {
'insert_something':"views.pyのinsert_something部分です。",
'name':'Bashi',
'test_titles': ['title 1', 'title 2', 'title 3'],
'form': TestForm(), # 追加
}
return render(request, 'webtestapp/index.html', my_dict)
追加箇所は、
- さっき作成した
forms.py
を使いたいのでインポート - テンプレートに渡して画面に入力フォームを表示したいので辞書の中に入れる。
.
.
.
<h1>index.html表示してます</h1>
<img src="{% static "images/test_img.png" %}" alt="表示できません">
<p>{{ insert_something }}</p>
<p>作成者は<b id='test'>{{ name }}</b>です。</p>
<form action="{% url 'webtestapp:index' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="送信">
</form>
<p>作成者は<b id="test">{{ name }}</b>です。</p>
.
.
.
↓みたいな表示が作れると思います。
追加箇所の解説
1. formの送り先
<form action="{% url 'webtestapp:index' %}" method="post">
HTMLのformで、送信先だけDjangoのテンプレート機能にて埋め込んでいる感じです。
ただ、このままだと、見た目ができただけなので送信ボタンを押しても何も起こりません。
2. フォーム使った攻撃対策
次に、{% csrf_token %}
という、最初見たら意味不明なのが書かれています。
簡単に触れますが、フォーム使った攻撃対策に必要な一文になります。これを自分で対策しようとすると結構面倒なのですが、よく使うのでDjangoが用意してくれています。
とりあえずいまは理解はいいので使っておきましょう。無いとエラーですし。
3. form 要素
{{ form }}
はviews.py
のテンプレートに埋め込むための変数のmy_dict
の中に入れたデータです。
importしてdictにいれただけなので、forms.py
で作れたフォームを埋め込んだということですね。
あと、送信ボタンはinput タグで追加してます。
views.pyに入力されたデータの処理記述
いまの状態だと送信ボタンを押しても何も起こらないので、送信ボタンを押してデータ送信したときDjangoが処理するデータ処理を書いていきましょう。
from django.shortcuts import render
from .forms import TestForm
def index(request):
my_dict = {
'insert_something': "views.pyのinsert_something部分です。",
'name': 'Bashi',
'form': TestForm(),
'insert_forms': '初期値', # 追加
}
# ---- 追加 ----
if (request.method == 'POST'):
my_dict['insert_forms'] = '文字列:' + request.POST['text'] + '\n整数型:' + request.POST['num']
my_dict['form'] = TestForm(request.POST)
# ---- 追加 ----
return render(request, 'webtestapp/index.html', my_dict)
{{ insert_forms|linebreaksbr }}
はinsert_forms
表示用に追加してます。
<p>{{ insert_forms|linebreaksbr }}</p>
<form action="{% url 'webtestapp:index' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="送信">
</form>
-
insert_forms
というのを追加しました。データを送信する前には「初期値」というのが表示 - 送信したあとはPOST送信されるのでif文の
my_dict['insert_forms']
の内容が入ります。データを使って、insert_forms
にデータを表示するための文字列を入れています。 -
my_dict['form'] = TestForm(request.POST)
で値を上書き。これを書くとフォームに入力した情報が残っているので送信ボタン押した後にも値を保持できて便利。 -
{{ insert_forms|linebreaksbr }}
のlinebreaksbr
というのはテンプレートで使えるタグです。\n
が改行を表す記号なのですが、HTMLでは機能しません。なのでlinebreaksbr
を使うことでHTMLの<br>
タグに変えています。
{{ insert_forms|safe }} は個人のローカルでテスト開発するなら別に必要ないです。不特定多数の人が触れる環境にデプロイするなどするならこのような箇所は気を付けましょう。
これでとりあえずできました。「初期値」の部分が2つのフォームに入力したものに変わります。
少しキレイに整える
今回はフォームが2つなのでそうでもないですが、
フォームが増えると1行にフォームが並び、汚くなります。
.as_table
とすると<tr><td>
タグでくくってくれます。
ついでに.as_ul
だと<li>
でくくります。
<p>{{ insert_forms|linebreaksbr }}</p>
<table>
<form action="{% url 'webtestapp:index' %}" method="post">
{% csrf_token %}
<tr>
<td></td>
<td>入力フォーム</td>
</tr>
{{ form.as_table }}
<tr>
<td></td>
<td><input type="submit" value="送信"></td>
</tr>
</form>
</table>
完成。ブラウザにて数値や文字列を渡せるのはアプリケーションを作る上でとても重要ですのでぜひ使っていただきたいです!
補足事項
forms.pyについて
今回forms.pyではエラーチェックとか制限などもうけなかったのですが、本来のforms.pyで行うのはそのようなバリデーション機能やデータの加工機能です。今後、追加していこうと思います。
formの送り先でapp_name指定した理由
<form action="{% url 'webtestapp:index' %}" method="post">
{% url '名前' %}
という書き方でURLを書く。
app_name='webtestapp'
urlpatterns = [
path('', views.index, name='index'),
]
app_name
がwebtestapp
でname='index'
なのでこのような書き方。
app_name='webtestapp'
を指定しないと{% url 'index' %}
となる。
今回は問題ないですが、アプリが増えた場合この書き方だと「index」というのが複数になったときに、どのindexを参照するの??とならないようにこのように書いています。
一連の記事
内容 | |
---|---|
part1 | 簡単な文字表示アプリを作る |
part2 | HTMLテンプレート表示 |
part3 | "画像" "CSS" "Javascript"実装 |
part4 | フォーム送信 ← ココ |
part5 | データベースの値取得・更新 |
番外編 | Django AWS デプロイ |
APIサーバー編 | Django REST frameworkとReact #4 |
参考
この章のコードは以下です。確認やコピペでどうぞ