Django2.0でブログの作成（その４：記事へのコメント）

その４

記事に対してコメントを表示させましょう。
commentはmodels.pyでDBを持ちますが、コメント入力フォームはforms.pyで作ります。
modelとformの違いはこちら、

[Djangoにおけるforms.pyとmodels.pyの違い](https://teratail.com/questions/45149)
modelsはDBに対応するものですが、formsは入力画面に対応するものです。 
modelsとformsを連携させたり、modelからformを作ることはありますが、 両者は別の責任を担います。

ふむ。
では早速。

# models.py
追加する。

```blog/models.py
class Comment(models.Model):
    post = models.ForeignKey('Post', on_delete=models.CASCADE)
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(
            default=timezone.now)

    class Meta:
        ordering = ['-created_date']
```
`'Post', on_delete=models.CASCADE`とは、Postが削除された時に、Commentも一緒に削除するということである。

# DB更新
`python manage.py makemigrations blog`
`python manage.py migrate blog`

# forms.py
ないので、新規作成します。
これは、コメント入力フォームからmodels.pyのCommentに繋げています。

```blog/forms.py
from django import forms
from . import models

class CommentForm(forms.ModelForm):
    class Meta:
        model = models.Comment
        fields = ('name', 'text',)
```

# views.py
以下のように、`def article`の中身を書き換えます。

```python:blog/views.py
(略)
from .models import Post, Comment #Comment追加
from . import forms #この行追加

(略)
def article(request, pk):
    article = Post.objects.get(id=pk)
    comments = Comment.objects.filter(post=article)

    if request.method == "POST": #入力フォームはPOSTなので
        form = forms.CommentForm(request.POST)
        if form.is_valid(): #もし、formの内容が正しい時は
            comment = form.save(commit=False) #formの内容はまだセーブしません！
            comment.post = article
            comment.author = request.user
            comment.save() #ユーザーを追加したのちにセーブ
    else:
        form = forms.CommentForm()

    print(article)
    return render(request, 'blog/article.html', {
        'article': article
        'form': form,
        'comments': comments
    }) #form と comment　を追加
```
return renderの中身も、`form`と`comment`を追加しておきます。

# urls.py
コメントは、article.html内に表記されるので、url自体は変わりません。
ここの変更はナシです。

# article.html
記事の下のところにこのような記述を追加します。

```html:article.html
    <div>
      <h3>コメント</h3>
      <form method="post" action="">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit">
      </form>
      <hr>
      {% for comment in comments %}
        author: {{ comment.author }}<br>
        name: {{ comment.name }}<br>
        {{ comment.text }}<br>
        <hr>
      {% endfor %}
    </div>
```

入力フォームは`<form method="POST" action=""></form>`
で括ります。
POSTは情報を送る方なので、セキュリティのために（クロスサイトリクエストフォージェリ(CSRF) を防ぐために）
`{% csrf_token %}`
というものを入れます。
また、{{form}}だけでもよいのですが、各コンテンツを<p>タグで括る場合
`{{form.as_p}}`とします。pじゃなくても大丈夫です。


# admin.py
最後にコメントのあれやこれやも管理ページから行えるようにするのであれば、

```admin.py
from django.contrib import admin
from .models import Post, Comment #Comment追加

admin.site.register(Post)
admin.site.register(Comment) #この行追加
```
しておくと、localhost:8000/adminからCommentsが見られるようになります！


# 確認
<img width="409" alt="スクリーンショット 2018-10-09 14.10.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/192887/3b2845b0-6ac5-13c1-dbe6-ee26de50e2fe.png">
loginuserは今は表示してありますが、本来ならば表示させるのはnameだけでよいでしょう。
しかし、loginuser(author)はあったほうがいいフォームのコンテンツです。
なぜなら、「書き込んだ人だけに削除権限を与える」ということをさせたいから！
次でやってみましょう。


# 参考情報
- [ Django の csrf_token について](http://d.hatena.ne.jp/blaue_fuchs/20111014/1318520988)
- [フォーム API](http://djangoproject.jp/doc/ja/1.0/ref/forms/api.html#as-p)