Djangoのフォーム（forms.py）を使ってデータを作成し、記録する（基礎の基礎３）

#1 はじめに
Djangoの<a href = "https://qiita.com/ykoji/items/ab8eb64f3903b0d7c1f2">１回目</a>、<a href = "https://qiita.com/ykoji/items/87cf343b92ebd0656107">２回目</a>で作ったものをベースに、今回は掲示板などの入力フォームを定義して、フォームに入力したデータをデータベースに保存するテクニックについて紹介をしたいと思います。（内容の利用については自己責任でお願いします）

#2 参照すべきサイト
Djangoの解説サイト（日本語）にフォームについて丁寧な解説があるので、ざっと目を通してみることをお勧めします。少し難しく感じる方もいらっしゃるかもしれませんが、これをみて感じをつかんでください。

https://docs.djangoproject.com/ja/3.2/topics/forms/

また、もしかしたらDjango GirlsのDjangoフォームに関する記事の方が読みやすいかもしれません。

https://tutorial.djangogirls.org/ja/django_forms/

#3 forms.pyの作成
models.pyと同じディレクトリ にforms.pyを作成します。
モデルは、models.pyで定義したArticleモデルをそのまま使います。また、フォームで表示させるフィールドを定義します。

```python:forms.py
from django.forms import ModelForm
from .models import Article
class ArticleForm(ModelForm):
    class Meta:
        model = Article
        fields = ["pub_date","headline","content","reporter"]
```

#4 views.pyの編集
views.pyに新しい関数formtestを追加します。

この関数は、最初にGETメソッドで呼び出した時(else:)は、formとしてArticleFormを呼び出し、form.htmlを使って入力フォームが表示されるようにレンダリングをします。

その後、フォームを入力して送信ボタンを押すとPOSTメソッドでリクエストが送られるので（if request.method == 'POST'）、formとして、入力したデータ（request.POST）が入ったフォームを定義します。そして、フォームのバリデーションが正常であれば（if form.is_valid）、モデルArticleのインスタンスを作成し、そこにデータを入れていきます。そして、最後に.save()をしてデータをデータベースに保存します。

これをコードにしたものが以下になります。必要なモジュールのインポートも忘れないようにしましょう。

```python:views.py
from django.http.response import HttpResponseNotAllowed
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .models import Reporter, Article
from .forms import ArticleForm

def hello(request):
    hw = 'Hello World!'
    return render(request, 'base.html', {'object':hw})

def modeltest(request):
    object_list = Article.objects.all()
    return render(request, 'modeltest.html', {'object_list':object_list})

def formtest(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            article = Article()
            article.pub_date = form.cleaned_data['pub_date']
            article.headline = form.cleaned_data['headline']
            article.content = form.cleaned_data['content']
            article.reporter = form.cleaned_data['reporter']
            article.save()
            return redirect('modeltest')

    else:
        form = ArticleForm()

    return render(request, 'form.html', {'form': form})  
```

レンダリングに必要なHTMLファイルは以下になります。{%csrf_token%}はクロスサイトリクエストフォージェリーというサイバー攻撃の一種を防ぐためにあらかじめDjangoが用意してくれている「おまじない」になります。これを入れていないとエラーが出ますので、忘れないようにしてください。

```html:form.html
<!DOCTYPE html>
<html>
 
<head>
    <meta charset="utf-8" />
    <title>フォーム</title>
</head>
 
<body>
    <h1>ユーザーフォーム</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">送信</button>
    </form>
</body>
 
</html>
```

#5.urls.pyの設定
formtest/にアクセスするとviews.pyの関数formtestが呼び出されるようにurls.pyを設定しておきます。

```python:urls.py
from django.urls import path
from .views import hello, modeltest, formtest

urlpatterns = [
    path('hello/', hello, name='hello'),
    path('modeltest/', modeltest, name = 'modeltest'),
    path('formtest/', formtest, name = 'formtest')
]
```
これで準備は終わりました。それでは実際にウェブサイトにアクセスしてみましょう。
127.0.0.1:8000/formtest/にアクセスして適当にデータを入力して、ボタンを押すと、127.0.0.1:8000/modeltest/に飛んで以下が表示されるはずです。

```
object_list:<QuerySet [<Article: テスト>, <Article: テスト2>, <Article: テスト3>]>
item:テスト
item.pub_date:July 25, 2021
item.headline:テスト
item.content:これはテストです。
item.reporter:投稿者１
item:テスト2
item.pub_date:July 25, 2021
item.headline:テスト2
item.content:test2
item.reporter:投稿者１```