知識の枝

"All is well"

Djangoで子モデルの数をテンプレートに渡す

約226日前 2021年4月14日18:04
デジタル
Django HTML

改訂履歴


2021/4/14 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回は親モデルに紐づいた子モデルの数をテンプレートで表示する方法を記します。


2. ゴール


子モデルのデータ数をhtmlテンプレートに渡して表示する。

3. 備忘録


3.1 - 親子関係


まず親モデルと子モデルについて。

親モデルというのは例えばこのブログ記事のようなものです。
記事ID、タイトル、本文、カテゴリ、タグなどの情報が保存されます。

子モデルとはこの記事についたコメントのことです。
コメントID、名前、本文、対象記事などの情報が保存されます。


親子の関係は子モデルの 対象記事 の部分で決まります。
コメントモデルで親となる対象記事を選択することで、記事とコメントが紐づきます。

この記事(親)についたコメント(子)はこの記事専用のもので、他の記事(他人)からは参照できません。


下記は親子モデルの例です。
models.py
class Post(models.Model):
title = models.CharField('記事タイトル', max_length=255, blank=True, null=True)
body = models.TextField('本文')

def __str__(self):
return self.title


class Comment(models.Model):
"""記事に紐づくコメント"""
name = models.CharField('名前', max_length=255, default='名無し')
text = models.TextField('本文')
target = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name='対象記事')
created_at = models.DateTimeField('作成日', default=timezone.now)

def __str__(self):
return self.text[:20]

ここで Postモデル は親Commentモデル は子となります。

Commentモデルの target '対象記事' で親を選べるようにします。
ForeignKeyで親モデル(Post)を指定することで、子モデルの作成時にPostの中から記事を1つ選択できるようになります。

3.2 - テンプレートへの渡し方


views.pyの中でテンプレートに渡すモデルを選択します。

関数ベースかクラスベースかでビューの書き方が異なりますが、やっていることは同じです。
ここでは関数ベースビューで書く場合を解説します。


まず親モデルのみをテンプレートに渡す場合です。
views.py
def Postlist(request):

posts = Post.objects.all()

context = {
"posts": posts,
}

return render(request, 'post_list.html', context)


ビュー名は Postlist
def Postlist(request):


posts という変数にPostモデル(投稿記事)を全て入れます。
posts = Post.objects.all()


テンプレートに渡す変数を辞書形式で指定します。
context = {
"posts": posts,
}
"posts" というKeyに 変数posts を持たせています。



最後にpost_list.htmlというテンプレートを表示します。
return render(request, 'post_list.html', context)
第3引数に先ほどの辞書を与えます。


htmlテンプレートの中で posts という変数を扱うことができるようになりました。
sample.html
{% for post in posts %}
<h1>記事タイトル:{{ post.title }}</h1>
<h2>本文</h2>
<h5>{{ post.body }}</h5>
{% endfor %}

変数postsに格納された記事モデルを1つずつ forループ で抜き出し、htmlで記事のリストを表示させています。

上記の例では postモデル の中身(タイトルや本文)を表示しています。
post.title   #タイトルが表示されます
post.body #本文が表示されます


さてここで、それぞれの記事に何件のコメントがついているか表示してみましょう。

先ほど同様にhtmlテンプレートにコメントの数を渡したいです。
そんなときはこうしましょう。
views.py
from django.db.models import Count #←インポート

def Postlist(request):

posts = Post.objects.annotate(comment_count=Count("comment"))

context = {
"posts": posts,
}

return render(request, 'post_list.html', context)
Post.objects にannotateを付け足すとテンプレートに渡す変数を拡張し、子モデルの数を表示できるようになります。

annotate(comment_count=Count("comment"))
comment_count=Count("comment")とすることで、テンプレートで post.comment_count と書いたとことが親記事に紐づいた子モデル(Comment)の数に置き換わります。

「comment_count」の部分はすきな名前でOKです。テンプレートで使いたい名前にして下さい。
「("comment")」部分は紐づいている子モデル名を入れます。今回はCommentモデルですので、"comment" が入ります。


さて、それでは表示してみましょう。
sample.html
{% for post in posts %}
<h1>記事タイトル:{{ post.title }}</h1>
<h2>■■本文■■</h2><h5>- コメント数:{{ post.comment_count }}件</h5>
<h5>{{ post.body }}</h5>
{% endfor %}


<htmlの表示例>
記事タイトル:Djangoで子のデータをテンプレートに渡す
■■本文■■- コメント数:1件
記事の内容・・・・
全ての投稿記事について、上記の構成でリストが表示されます。


4. さいごに


親モデルに紐づいた子モデルの数を表示できるようになりました!
不明な点があればコメント下さい。お疲れ様でした。