お店を自由に追加してみよう！CreateView編

#今回はCreateView編です。
今までTemplateViewを用いてListView、DetailViewを作成してまいりました。
[その１－TemplateViewを使ってみよう！IndexView編](https://qiita.com/flee-style/items/ab99a3d6b568c4b674b5)
[その２－TemplateViewをつかってみよう！Detailview編](https://qiita.com/flee-style/items/a8ec6929e798ffd9f0e2)
お店の一覧、お店の詳細ページを表示ができるようになっている状態の続きと致します。

自分で好きなデータを追加できるって掲示板みたいで楽しいですよね！！

##（見慣れない技術の解説）forms.pyでフォームの定義をおこなう
ここであらたなフォームという技術が現れました。
このforms機能はお仕事ではかなり使われることが多いので、慣れておくことを絶対にお勧めしています。
これは何なのかというと、pythonでこのform部分を作ってしまい、モデルと連動してhtmlの\<form>\</form>を作成することになります。
最終的にwebサイトのフォーム部分を表示させることが目的となっていますので、怖がらずで大丈夫ですよ！

##編集するファイルはこちら
```
mysite
│  db.sqlite3
│  manage.py
├─mysite
│  │  settings.py
│  │  urls.py
└─test_app
    │  admin.py
    │  apps.py
    │  models.py
    │  tests.py
    │  urls.py(ここをルーティング設定のために編集)
    │  views.py(ここをCreateView設定のために編集)
    │  forms.py(ここにお店追加の投稿フォームclassを作成)
    ├─migrations
    └─templates
    　  └─test_app
    　       └─list.html(ここにお店追加のリンクを表示)
               detail.html
               form.html(お店追加の投稿フォームを表示)
```
#ルーティング設定
このURLでお店の作成ページにリンクできるように設定します。

```
http://localhost:8000/create
```
test_appのurls.pyにルーティングを設定します。

```urls.py
from django.urls import path
from . import views

app_name = 'test_app'
urlpatterns = [
    path('index/',views.IndexView.as_view(),name='index'),
    path('<int:pk>/',views.DetailView.as_view(),name='detail'),
    path('create/',views.CreateView.as_view(),name='create'),#(ここを追加)
]
```
解説：`app_name`とは、どのアプリ名に対してのルーティングファイルであるか指定する必要があります。ページ上のリンク（htmlで書かれたページのaタグで書かれたリンク）で`<a href="{% url 'test_app:create' %}">`と記述するため、`test_app`とアプリ名を設定する必要があります。
また、`path('create/',views.CreateView.as_view(),name='create')`ではcreate/のURLでviews.pyのCreateViewを呼び出しています。as_view()はテンプレートビューをビューとして扱うため使用されています。このas_view()を付けることによりビュー定義の記述がぐっと楽になります。テンプレートビュー限定のメリットですね。

#CreateViewをviews.pyに設定

```views.py
from django.views import generic
from .models import Shop
from .forms import ShopCreateForm #ここを追加

# Create your views here.
class IndexView(generic.ListView):
    model = Shop
    template_name = 'test_app/list.html'
class DetailView(generic.DetailView):
    model=Shop
    template_name = 'test_app/detail.html'

class CreateView(generic.CreateView):#ここ以降を追加
    model = Shop
    form_class = ShopCreateForm
    template_name = "test_app/form.html"
    success_url = "/index"
```
解説：`form_class`にforms.pyで投稿フォーム用に今回作成するフォームクラスである`ShopCreateForm`を指定しています。
ちゃんと`import ShopCreateForm`を忘れずにお願いします。

views.pyとforms.pyを作成し、行ったり来たりするため、慣れるまで時間がかかりますが頑張りましょう！焦らず無理せず。
きっと慣れてさらに先に進めます！

#お店投稿フォームをforms.pyに作成
forms.pyが作成されていない場合、新たに作成する場合があります。作成する場所はtest_appの直下です。views.pyやmodels.pyと同じレベルに作成します。
forms.pyはこのようになります。

```forms.py
from django import forms
from .models import Shop

class ShopCreateForm(forms.ModelForm):
    class Meta:
        model = Shop
        fields = ("name","tell_num","address")
```
解説：forms.ModelFormとは、フォームを作成するためのdjangoの機能となっています。
モデルで定義されているフィールドをそのまま使います。
そのなかで、`fields`にてフォームで表示させるフィールドを選び、絞ることができます。

お店のデータを投稿したい場合、すでにShopのフィールドは作成されています。実際にmodels.pyの内容はこちらで、`name`や`tell_num`、`address`、`created_at`などフィールドが作成されています。

```models.py
from django.db import models

# Create your models here.
class Shop(models.Model):
    #各フィールドの定義
    name = models.CharField('shopname',max_length=30)
    tell_num = models.CharField('tell_number',max_length=13)
    address = models.CharField('address',max_length=30)
    created_at = models.DateTimeField(auto_now_add=True)

    #admin画面の表示内容
    def __str__(self):
        return self.name
```
このShopクラスのフィールドをそのままforms.pyで使うことを意味しているのです。
ModelFormを用いると大変楽にフォームページを作成できるのです！

#投稿ページのform.htmlを作成

```mysite/test_app/templates/test_app/form.html
<!DOCTYPE>
<html>
    <head>
    </head>
    <body>
    <p>お店の作成</p>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit">save</button>
        </form>
    </body>
</html>
```
解説:`<form method="post">`でフォームタグを作成しています。
`{% csrf_token %}`はフォームデータに改ざん防止の特殊な何かのデータを添えて送信するもので、必須です。
これを入れないと、djangoがエラーとなるため、必ず入れましょう。
`{{ form.as_p }}`はforms.pyで作成したShopCreateFormをviews.pyの`form_class`で指定していたため、html側では`form`と記述するだけでフォームが呼び出せます。`form`と書く、と刷り込ませて良いです！
`<button type="submit">save</button>`ではデータ送信ボタンを作成しています。」

#「お店の投稿」リンクを一覧ページに作成

```test_app/templates/test_app/list.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
  <p>一覧の表示</p>
  <p><a href="{% url 'test_app:create' %}">お店の追加</a></p><!-- この行を追加 -->
  <table>
    <tr>
    </tr>
    {% for shop in shop_list %}
    <tr>
      <td>{{ shop.name }}</td>
      <td><a href="{% url 'test_app:detail' shop.pk %}">詳細</a></td>
    </tr>
    {% endfor %}
  </table>
  </body>
</html>
```
解説：お店の追加ページへリンクするためにリンクを書いています。パスは`test_app`というアプリ名の`create`を指定しています。

#formの表示の確認を行う
「お店の追加フォーム画面」で団子屋という名前のお店を追加してみます。
![create画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/12885b8f-0bbb-e768-12e9-8c155783cbad.png)

「リスト画面」で追加されたデータを確認してみましょう。
![クリエイト後トップ画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/2174d3fb-af54-6fd3-f0b3-d57bf89b01ff.png)

「団子屋詳細画面」で団子屋の詳細を確認してみましょう。
![団子屋詳細ページ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547305/e1325bcc-ca0b-5d02-0b0f-3c57a73391e9.png)

お疲れさまでした✨
#最後に
データ追加のための設定は必ずと言っていいほど重要なdjangoスキルとなるでしょう。CreateViewを用いてスピーディに作成ができることでかなりDjangoに慣れているといえると思います。
３つくらい自分でアプリを作成してみれば、データの追加、詳細、一覧が含まれるような、お店掲示板、日記などのアプリケーションが作成できるようになっていると思います。

わからないところや質問など受け付けておりますので、一緒に頑張ってゆきましょう！