フォームを作成しました。

## htmlでのformタグの使い方。

Webサイトで見かけるフォームでは、テキスト入力欄やボタン等、多くのパーツが用意されているが、その簡単な使い方を下に乗せる。

### フォーム欄を作るformタグ
記述する属性
"action"→データの送信先ページを指定
"method"→データの転送方法の指定。主にgetかpostを入力。
"name"→フォームの名前を指定

```
例)<form action="example.php" method="post" name="content-form"
　　　　　　ここにフォームの部品を入れる。
   </form>   
```
この例だと、フォームに入力したデータがexample.phpへ送信され処理される。

### inputタグ
formタグで用いるパーツは、inputタグがほとんど。type属性で用途別に表示するパーツを変える。
```
<input type="text"> //一行のテキスト入力欄出現
ちなみに、あらかじめテキストを表示させる方法として、placeholder属性を使う。

<input type="radio"> //ラジオボタン出現
属性：name(ラジオボタンの名前), value(送信される選択肢の値), checked(最初から選択されている状態を作る)

<input type="checkbox"> //チェックボックス出現。複数の選択肢を選べるやつ。
属性：name(チェックボックスの名前), value(送信される選択肢の値), checked(最初から選択されている状態を作る)

<input type="submit"> // 送信ボタン出現
属性: name(ボタンの名前), value(ボタンに表示するテキスト)

<input>タグ以外にも、<textarea>タグと呼ばれる、複数行のテキスト入力欄を作るものもある。

```

### フォームのラベルを作る
フォームを作る際に、テキスト入力欄横に、「名前」,「電話番号」などの文字を表示させるが、これらのテキストを「ラベル」と呼ぶ。

"label"タグを使えば、フォームのパーツとラベルが関連付けられる。そうすると、そのテキストも含んだ選択し全体がクリックできるようになる。
```
使い方
ラベルテキストの部分を<label>タグで囲み、for属性をつける。
関連付けさせたいフォームのパーツにはid属性をつける。
このfor属性とid属性の値を同じにすればフォームとパーツが関連付けされる。

<input type="checkbox" nanm="travel" value="日本国内" id="japan">
<label for-"japan">日本国内</label>
```
↑こうすると、inputで作ったチェックボックス欄のid属性と、labelで囲ったfor属性が同じなため、関連付けされる。すると、ラベル(日本国内)の部分にカーソルを当ててクリックしても、チェックボックスに反映される。

## Djangoでやってみよう
index.html
```
<form action="{ % url 'form' %}" method="post">
        {% csrf_token %}
        <label for="msg">message: </label>
        <input id="msg" type="text" name="msg">
        <input type="submit" value="click">
</form>
```
{% url 'form' %}を使用すると、指定されたURLパターン（この場合は名前が'form'であるパターン）に対応するURLのパスが生成される。つまり、'form'という名前で登録されたURLパターンがurls.pyで定義されていると仮定すると、そのパスが生成される。

例えば、urls.pyで以下のようにURLパターンを書く。
```
urlpatterns = [
    path('', views.index, name="index"),
    path('form', views.next, name="form")
]
```
ここで、name='form'という名前で/form/パスが定義されています。この場合、{% url 'form' %}は/form/という文字列を生成。
つまり、<form action="{% url 'form' %}" method="post">というHTMLのフォームは、action属性に/form/というURLパスが設定され、そのフォームが送信されるときにはそのパスにデータが送信されることになる。(ChatGPTさんに教えてもらいました。ちとムズイ(´;ω;｀))

#### もう一つ気になる部分。それは、{% csrf_token %}

{% csrf_token %}は、Djangoのテンプレートタグの1つで、クロスサイトリクエストフォージェリ（CSRF）保護を提供するために使用される。
CSRF攻撃は、ユーザーがログインしているサイトに対して不正なリクエストを送信する攻撃です。Djangoでは、これを防ぐためにCSRFトークンを使用。

よくわからないけど、これをつけると、外部の攻撃から守ってくれる！てっことだと勝手に解釈。とりまフォームを作るときにはつけておこう。

## views.py
```
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    params = {
        "title": "practice/index",
        "msg" : "お名前は？",
    }
    return render(request, "practice/index.html", params)

def form(request):
    msg = request.POST["msg"]
    params = {
        "title": "Hello/Form",
        "msg": "こんにちは、'+ msg +' さん。",
    }
    return render(request, "practice/index.html", params)
```
indexが、そのままWebブラウザからアクセスしたときの処理で、formがフォーム送信を受け取ったときに表示する処理。

### フォームの値はrequest.POSTで取得！
```
msg = request.POST["msg"]
```
これが、フォームの値を取り出している部分。
index.htmlのフォームには、name="msg"と指定された<input type="text">タグが用意されていた。このname="msg"に記入されたデータを取り出しているのが、msg = request.POST["msg"]。

:::note info
クエリパラメータを取り出したのは？
request.GET
POSTはフォームから送信された値を取り出すのに役立つ。
:::
### Webブラウザで実際にアクセスしてみた！
![スクリーンショット 2024-05-06 015224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779281/7ab4b6d3-fb33-5628-8869-71cc718a0625.png)

名前を入力すると…
![スクリーンショット 2024-05-06 015231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779281/4911db74-4049-9cff-95c4-396fdcfefdfc.png)

しかし、このままだと、もう一度フォームを送信すると、前回書いた内容が残らない。。

## 送られてきた内容を残すためにはどうすればいいか？
### Formクラスを使う。
Formというクラスを作成して、そこでフォームの内容を定義しておく。

forms.pyを作る。

```
from django import forms

class HelloForm(forms.Form):
    name = forms.CharField(label="name")
    mail = forms.CharField(label="mail")
    age = forms.IntegerField(label="age")
```

もともとDjangoで用意された"form"クラスを継承して、自分のクラスを作っている。だから、こんな短い行で済んでいる！

forms.CharFieldはテキストを入力するフィールドクラス。
forms.IntegerFieldは整数の値を入力するためのフィールドクラス。

### views.py
```
from django.shortcuts import render
from django.http import HttpResponse
from .forms import HelloForm

def index(request):
    params = {
        "title": "practice/index",
        "message": "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, "practice/index.html", params)

```
#### "form": Helloform() 
テンプレートファイルにて、"form"という変数に、Helloformクラスを作る。このHelloformクラスは、フォームを作る関数が定義されているため、実質、ここでフォームが作られる。
##### if(request.method == "POST"):
POST送信されたときに、以下のコードを実行するということ。request.methodはどういう方式で、アクセスしたかをチェックしている。

:::note info
GETは用意されているデータをただ取り出すだけの処理。→ページを表示するだけ
POSTは新しいデータを作って受け取るような処理。→フォームを表示しているページのフォームに、ユーザが組み込んだ情報が送られるのでPOST。

これらをHTTOメソッドといい、Webページなどをインターネットでやり取りするときのプロトコル（手続き）。
:::

:::note warn
私はfrom .forms import HelloFormを書くのを忘れており、一時間無駄にしました。なぜ必要なのか、ChatGPTの説明を載せておきます。
↓↓↓
from .forms import HelloForm は、Django プロジェクト内の同じディレクトリ（モジュール）内の forms.py ファイルから HelloForm クラスをインポートしています。

この行は、現在のディレクトリ（モジュール）から forms.py を参照して、その中で定義されている HelloForm クラスを取り込んでいます。from .forms の部分は、現在のディレクトリ（モジュール）から forms.py を参照することを意味し、.forms の . は現在のディレクトリを表します。

なぜ必要なのかというと、この行は HelloForm クラスを使うために、それを定義しているファイルである forms.py から HelloForm クラスを読み込む必要があるからです。Pythonでは、あるファイルに定義されたクラスや関数を別のファイルから使う場合、そのクラスや関数を定義しているファイルをインポートする必要があります。
:::


### index.html
```
{% load static %}
<!DOCTYPE html>
<html>
<head lang="ja">
    <meta charset='utf-8'>
    <title>{{title}}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'practice/css/style.css' %}">
</head>
<body>
    <h1> {{title}}</h1>
    <p>{{message|safe}}</p>
    <form action="{% url 'index' %}" method="post">
        {% csrf_token %}
        {{form}}
        <input type="submit" value="click">
    </form>
</body>
</html>

```
{{message|safe}}の|safeはフィルターという機能で、HTMLタグを書き出せるようにするためのもの。Djangoのテンプレートでは、{{}}で値を出力するとき、HTMLのタグが含まれていると自動的にエスケープ処理（HTMLタグを使わずただのテキストとしてそのまま出力）する。それを防ぐもの。

### 結果
![スクリーンショット 2024-05-06 030245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779281/255cc9e6-6bc0-cdac-49ed-91173e8b918c.png)