【Django】CreateViewの使い方

#はじめに
備忘録として乗せていますので文章適当です。
時間がある時に綺麗に書き直したいと思います。

今回は記事を投稿するサイトを作成する際に、
新規投稿を行うページを作成する時にCreateViewを使ったので
その時の手順などを記載します。

何か新しくデータを作るときはCreateViewを使うと覚えているので
とりあえずCreateViewを採用しました。

実装に関係あるかわかりませんが、
MDBのindex.htmlの内容をコピペして、
CDNの内容もコピペしています。

#実装手順

下記の手順で実装します。
１. model作成
２. forms.py作成
３. views.py修正
４. urls.py修正
５. html作成

##model作成
まず、models.pyにモデルを定義します。

データベースに値を格納するためにもモデルの定義は必須になります。

モデルを定義する際には
`from django.db import models`のmodelsを使用します。
(最初から記載されているはず。)

下記のようにクラスを定義します。

```
class モデル名(models.Model):
```
中の変数たちは、いわゆるカラム？です。
ここら辺の`models.CharField`などはご自身で調べてください・・・。すみません。

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


class Post(models.Model):
    title = models.CharField(verbose_name="タイトル", max_length=50, null=False, blank=False)
    content = models.TextField(verbose_name="内容", max_length=2000, null=True, blank=True)
    created = models.DateTimeField(verbose_name="投稿日時", auto_now_add=True, null=False, blank=False)
    updated = models.DateTimeField(verbose_name="更新日時", auto_now=True, null=False, blank=False)

    def __str__(self):
        return self.title
```

モデル定義後にターミナルにて下記コマンド実行（models.py更新後は毎回)

```
$ python manage.py makemigrations
$ python manage.py migrate
```

OKと表示されれば成功です。

djangoの管理画面でモデルを見れるようにします。

今回は記事の情報を入れていくので
`ordering = ('-created',)`で上から新しい順にしています。

```python:admin.py
from django.contrib import admin

from .models import Post


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    # admin画面に表示する内容（タプル型） 
    list_display = ('title', 'content', 'created')
    # admin画面でどの項目をタップしたら詳細にいくか
    list_display_links = ('title',)
    # 並び替え
    ordering = ('-created',)
```

##forms.py作成
自分のアプリ配下にforms.pyを作成します。

`PostForm`の部分は任意の名前で大丈夫だと思います。

```python:forms.py
from django import forms

from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        # どのモデルをフォームにするか指定
        model = Post
        # そのフォームの中から表示するフィールドを指定
        fields = ('title', 'content')

    # フォームを綺麗にするための記載
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
```

##views.py修正

次にviews.pyの修正を行います。
一部抜粋して表示しています。

`form_class`には先ほど作成したformの名前を指定します。
そのために`from .forms import PostForm`で読み込んでいます。

`get_success_url`は投稿に成功した時に実行される処理で、
returnで投稿後の画面先を指定します。

今回は投稿に成功したというメッセージを表示したいのでこの関数を定義し、
`messages.success(self.request, '記事を投稿しました。')`を記述しています。

```python:views.py
from django.contrib import messages
from django.shortcuts import resolve_url
from django.urls import reverse_lazy
from django.views.generic import CreateView

from .forms import PostForm
from .models import Post


class PostCreate(CreateView):
    model = Post
    form_class = PostForm
    # 投稿に成功した時のURL
    success_url = reverse_lazy('diary_app:index')

    # 投稿に成功した時に実行される処理
    def get_success_url(self):
        messages.success(self.request, '記事を投稿しました。')
        return resolve_url('diary_app:index')
```

##urls.py修正

次にurls.pyを修正します。

CreateView作成時のurls.pyの内容です

先ほどviews.pyで定義した`PostCreate `を紐づけています。

```python:urls.py
from django.urls import path

from . import views


app_name = 'diary_app'

urlpatterns = [
    path('', views.Index.as_view(), name="index"),
    path('detail/<int:pk>', views.PostDetail.as_view(), name="post_detail"),
    path('create', views.PostCreate.as_view(), name="post_create"),
]
```


##html作成
次に実際にWeb常に表示するhtmlファイルの作成を行います。

アプリフォルダ > templatesフォルダ > アプリ名フォルダ >`post_form.html`を作成します。
templatesフォルダの配下に作成しないと読み込まれないので注意！

アプリ名フォルダの配下に作る必要があるのかはわかりません。
多分templatesの配下に作っても読み込むと思います。

また、ファイル名はpost_form.htmlでないと読み込まれないので同じにしてください。

これも、モデル名_form.htmlなのかpost_form.htmlなのか、
よくわかっていないので今度時間がある時に調べたいと思います。

post_form.htmlの内容は下記のようになります。

私の場合は、base.htmlというファイルを作成し、
そちらに`{% block main %}`と言った定義をしているので下記のようになります。

何を行っているのか分からない方は django extends とかで検索したらでてくると思います？

`method="POST"`はデータベースにPOSTするという意味なので必要
`{% csrf_token %}`はデータベースとの通信のセキュリティかなんかの記述なので必要
`{{ form.as_p }}`で、forms.pyで定義したfieldsの内容が表示されます。
ボタンの`type="submit"`とすることでボタンを押すとデータベースにデータを送ります。

```python:post_form.html
{% extends "diary_app/base.html" %}

{% block main %}
    <br>
    <h1>投稿・更新ページ</h1>
    <br>
    <form action="" method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="btn btn-primary">保存</button>
    </form>
    <br><br>
{% endblock %}
```

こんな感じになりました。
![スクリーンショット 2021-04-28 1.14.57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/8c47cd3b-2d07-8a73-434b-67056c5e5bf8.jpeg)

# さいごに

眠かったのと本当に自分専用の備忘録として投稿しているので
内容が結構雑なものになってしまいました。

もし何か質問がありましたらコメントしていただけますと幸いです。

ですが私も初学者なので答えられるかわかりません。(笑)

また、私が学習に使った教材は、[こちら](https://www.udemy.com/share/103vMQAEAecltbTHwH/)になります。

クーポンを使って3200円くらいでしたのでお手頃かと思います。

気になった方はぜひ見てください！

以上、最後までご覧いただきありがとうございました。