背景
作りたいもの
→ スニペットやブログのコメント欄を作成したい。
わからなかったこと
→ views.pyファイルで一つのモデルを指定しているため、同じテンプレート内で他のモデルを指定できるのか、できるとしたらどう書けばいいのかわからない。
作成したモデル
models.py
# スニペットモデル
class Snippet(models.Model):
title = models.CharField('タイトル', max_length=128)
code = models.TextField('コード', blank=True)
description = models.TextField('説明', blank=True)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="投稿者",
on_delete=models.CASCADE
)
created_at = models.DateTimeField("投稿日", auto_now_add=True)
updated_at = models.DateTimeField("更新日", auto_now=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.title
#コメントモデル
class Comment(models.Model):
text = models.TextField('コメント', blank=False)
commented_to = models.ForeignKey(Snippet, on_delete=models.CASCADE) # 参照元のスニペットが削除されたらコメントも削除される。
commented_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="コメント投稿者",
on_delete=models.CASCADE
)
commented_at = models.DateTimeField('投稿日', auto_now_add=True)
def __str__(self):
return self.text
スニペットモデルとコメントモデルは、一つのスニペットに対して複数のコメントが紐づけられた1対多のリレーションのため、ForeignKeyを用いた。
ここではスニペットモデルを親モデル、コメントモデルを子モデルと呼称することとする。
解決策
親モデル.子モデル_set.all と記載することで子モデルのオブジェクトを取り出す事ができた。
snippet_detail.html
<!-- スニペット部分は省略 -->
<br><br>
{% if snippet.comment_set.all %}
<h2>コメント一覧</h2>
<div class="comment_list" style="background-color:#EDF7FF;" >
{% for comment in snippet.comment_set.all %}
<div class="comment-text">
<p>◆{{ comment.text }} by {{ comment.commented_by }} {{ comment.commented_at}}</p>
</div>
{% endfor %}
</div>
{% endif %}
実際の完成品がこちら。
デザインのセンス、HTMLの理解がなさすぎて見た目は酷いものだがなんとか出す事ができた。
おわりに
次の投稿ではForeignKeyで紐づけていないモデルでも一つのテンプレートで表示する方法をご紹介します!
また、別の方法を紹介されている方の記事も見つけたのでこちらも参考にしてみてください。
「ForeignKey 子モデル 逆参照」とかで検索すると結構出てきます。
けど日本語だとやはり情報が少ないですね、、