Django#3（フォームの値を受け取る）

# Django#3（フォームの値を受け取る）

## 内容

- テンプレートにフォームを設置する。
- POSTリクエストを受け取る
- リクエストの変数と値の取り出し
- レスポンスを返す（正常）

## 下準備

下記の内容でhelloを設定している事。

[Django\#1（初期設定とhello） \- Qiita](https://qiita.com/nab/items/ceb301be22f71b915ba3)

## URL.py

設定に変更なし。GETもPOSTも同じ設定で受け取れる。

## テンプレートにフォームを記述する。

テンプレートファイルを下記の通りに修正する。

```html:template/hello.html
<html>
<body>
  <form action="/hello" method="post">
    {% csrf_token %}
    <div>
      <label for="name">名前</label>
      <input type="text" id="name" name="name">
    </div>
    <div>
      <label for="email">メールアドレス</label>
      <input type="mail" id="email" name="email">
    </div>
    <div>
      <label for="message">内容</label>
      <textarea id="message" name="message">{{ message }}</textarea>
    </div>
    <input type="submit" value="送信する">
  </form>
</body>
</html>
```

説明。

- `{% csrf_token %}`タグについて
  - POSTメソッドはCSRF対策としてトークンで照合を行っている。
  - そのトークンを設定するのがこのタグ。formタグ内に書く。処理は自動的に行われる。
  - これが無いと不正アクセスとしてエラーが発生する。
  - formが複数ある場合は、各formにそれぞれ書く。
- その他のフォーム部分は普通のHTMLで書ける。
  - DBと紐づけて半自動で生成することも可能。今回はやらない。

## views.pyにPOSTリクエストを受け取る処理を追記する。

views.pyのHelloViewにpostメソッドを追記する。

```python:views.py
class HelloView(View):
    def get(self, request, *args, **kwargs):
        context = {
            'message': "Hello World! from View!!",
        }
        return render(request, 'hello.html', context)

    def post(self, request, *args, **kwargs):
        context = {
            'message': "POST method OK!!",
        }
        return render(request, 'hello.html', context)

hello = HelloView.as_view()
```

説明

- getメソッド
  - 特に変更なし。
- postメソッド
  - まるっと追加。内容はgetとほぼ同一。区別できるようにメッセージだけ変更。
- 動作としては、HTTPリクエストのリクエストメソッドに応じて  
  ビュークラス内のgetメソッドかpostメソッドが実行される。
  - なので、全く別の処理にしてもOK、同一の動作ならまとめるのもOK。今回はべた書き。
  - pushとかdeleteへの挙動は不明。ブラウザ自身がgetとしてリクエストしてしまうので。

## 動作確認

この時点で、`http://IPアドレス:8000/hello`にアクセスすると下記のような画面が表示される。

![Clipboard01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/bc46e72c-7d7e-bbda-978b-0e128f3aaf20.jpeg)


ボタンをクリックすると下記のような画面が表示される。

![Clipboard02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/72293fa0-d10f-8cf6-057d-619dd8532df3.jpeg)


テキストボックスのメッセージがこの画面のように表示されていたら、POST用の処理が正しく呼び出されている。  
まだ、フォームに入力した文字は保持されない。その処理は以下。


## HTTPリクエストからフォームの入力値を取り出す

次に、POSTリクエストからフォームの入力値を受け取る方法。  
HTTPリクエストに付随する情報はビュークラスのget, postメソッドの2番目の引数に入ってくる。  
具体的には下記の`request`

```python
    def post(self, request, *args, **kwargs):
```

このrequestの詳細は下記ドキュメントを参照。ここではとりあえずフォームの入力値だけ取り出す。

[リクエストとレスポンスのオブジェクト \| Django ドキュメント \| Django](https://docs.djangoproject.com/ja/2.1/ref/request-response/)

値の取得は`request.POST['フォームのID']`でOK。  
このうち、request.POSTがDjangoのQueryDictという型で、Pythonの辞書型の拡張になっている。  
フォームの入力値は普通に辞書型のようにアクセスできる。

QueryDict型の詳細は下記を参照。

[QueryDict](https://docs.djangoproject.com/ja/2.1/ref/request-response/#django.http.QueryDict)

## レスポンスを返す

フォームの入力値にアクセスする手段が分かったので、ビュー関数とテンプレートを修正して、  
入力値をそのまま埋め込んで返す処理を書く。

まずビュー関数の修正。request.POSTの値をそのままname, email, messageの各変数に設定している。

```python:views.py
    def post(self, request, *args, **kwargs):
        context = {
            'name': request.POST['name'],
            'email': request.POST['email'],
            'message': request.POST['message'],
        }
        return render(request, 'hello.html', context)
```

次いでテンプレートの修正。差分のみ記載。valueを付け加えた。

```diff
7c7
<       <input type="text" id="name" name="name" value="{{ name }}">
---
>       <input type="text" id="name" name="name">
11c11
<       <input type="mail" id="email" name="email" value="{{ email }}">
---
>       <input type="mail" id="email" name="email">
```

動作確認。http://IPアドレス:8000/helloにアクセスして、フォームに何か入力して、  
ボタンをクリックして、入力した文字がそのまま残っていたらOK

![Clipboard03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170209/6a496038-1a91-f20b-3233-009db9c3a35a.jpeg)


入力値のチェックやDBと連携して保存したりとかの処理はまた別途。