20
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python Django】初心者プログラマーのWebアプリ#4 【フォーム送信】

Last updated at Posted at 2018-06-23

第四回目Python Djangoフレームワークを使ったフォーム機能を実装。
初心者プログラマー用のwebアプリ作成チュートリアル始めます。前回は画像, CSS, JavaScriptを使う方法でした。

フォームを使えるようになると入力情報してもらうことで一般的なWEBアプリだけでなく、AI、画像認識機械学習、自然言語系の機械学習だろうが入力されたフォームの情報を使って役に立つWebアプリで使えるようになると思います。

Pythonを使っているならぜひ身につけておきたいところですね。
pngwing.com (1).png

内容が古くなったのでDjango 3で記事更新しました。 updated: 2021/09

:pushpin: 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

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なら数値を▲ ▼押したら増減できるフォーム

を作れます。楽です。
↓文字入力と数値入力フォーム
image.png

以下からは、前回までの続きなので今回のフォーム送信には関係無いものもありますので適時読み飛ばしや追加などしてください。

views.pyに記述

では、最初にformがどんな感じか見るために画面に表示させてみましょう。

testproject/webtestapp/views.py
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)

追加箇所は、

  1. さっき作成したforms.pyを使いたいのでインポート
  2. テンプレートに渡して画面に入力フォームを表示したいので辞書の中に入れる。
testproject/webtestapp/templates/webtestapp/index.html
.
.
.
    <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>
.
.
.

↓みたいな表示が作れると思います。

image.png

追加箇所の解説

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が処理するデータ処理を書いていきましょう。

testproject/webtestapp/views.py
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表示用に追加してます。

testproject/webtestapp/templates/webtestapp/index.html
    <p>{{ insert_forms|linebreaksbr }}</p>
    <form action="{% url 'webtestapp:index' %}" method="post">
      {% csrf_token %}
      {{ form }}
      <input type="submit" value="送信">
    </form>
  1. insert_formsというのを追加しました。データを送信する前には「初期値」というのが表示
  2. 送信したあとはPOST送信されるのでif文のmy_dict['insert_forms']の内容が入ります。データを使って、insert_formsにデータを表示するための文字列を入れています。
  3. my_dict['form'] = TestForm(request.POST)で値を上書き。これを書くとフォームに入力した情報が残っているので送信ボタン押した後にも値を保持できて便利。
  4. {{ insert_forms|linebreaksbr }}linebreaksbrというのはテンプレートで使えるタグです。\nが改行を表す記号なのですが、HTMLでは機能しません。なのでlinebreaksbrを使うことでHTMLの<br>タグに変えています。

{{ insert_forms|safe }} は個人のローカルでテスト開発するなら別に必要ないです。不特定多数の人が触れる環境にデプロイするなどするならこのような箇所は気を付けましょう。

キャプチャ.JPG

これでとりあえずできました。「初期値」の部分が2つのフォームに入力したものに変わります。
キャプチャ.JPG

少しキレイに整える

今回はフォームが2つなのでそうでもないですが、
フォームが増えると1行にフォームが並び、汚くなります。

.as_tableとすると<tr><td>タグでくくってくれます。
ついでに.as_ulだと<li>でくくります。

testproject/webtestapp/templates/webtestapp/index.html
    <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>

キャプチャ.JPG

完成。ブラウザにて数値や文字列を渡せるのはアプリケーションを作る上でとても重要ですのでぜひ使っていただきたいです!

補足事項

forms.pyについて

今回forms.pyではエラーチェックとか制限などもうけなかったのですが、本来のforms.pyで行うのはそのようなバリデーション機能やデータの加工機能です。今後、追加していこうと思います。

formの送り先でapp_name指定した理由

<form action="{% url 'webtestapp:index' %}" method="post">
{% url '名前' %}という書き方でURLを書く。

urls.py
app_name='webtestapp'
urlpatterns = [
    path('', views.index, name='index'),
]

app_namewebtestappname='index'なのでこのような書き方。

app_name='webtestapp'
を指定しないと{% url 'index' %}となる。

今回は問題ないですが、アプリが増えた場合この書き方だと「index」というのが複数になったときに、どのindexを参照するの??とならないようにこのように書いています。

:pushpin: 一連の記事

内容
part1 簡単な文字表示アプリを作る
part2 HTMLテンプレート表示
part3 "画像" "CSS" "Javascript"実装
part4 フォーム送信 ← ココ
part5 データベースの値取得・更新
番外編 Django AWS デプロイ
APIサーバー編 Django REST frameworkとReact #4

参考

この章のコードは以下です。確認やコピペでどうぞ

20
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?