質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.01%

teratailの回答投稿数を表示するロジック

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 762

mulberryfields

score 780

Djangoで、質問投稿サイトを作成しています。
teratailのトップページでは、質問の一覧の中に各質問の回答数も表示しています。
同じことをしたいのですが、どのように作成していると思いますか?

私のサイトのモデルは、下記のとおりです。

#modesl.py
#質問を扱うクラス
class Question(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    votes = models.IntegerField(default=0)
    datetime = models.DateTimeField(auto_now=True)

#回答を扱うクラス
class Answer(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    content = models.TextField()

そして、質問一覧表示にあたっては、

#views.py
def index(request):
    latest_question_list = Question.objects.order_by('-datetime')[:10]
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))


という形でデータを取り出し、レンダリングして表示させています。
最新のデータから10個を取り出して表示するようにしています。

私は、回答投稿数を表示するための方法として、下記の2つを思い付きました。
1.回答が投稿されると、Questionに回答数が記録されるようにする。
・Questionクラスに、
answercnt = models.IntegerField(default=0)
を登録しておく。
・回答投稿時に、views.pyにおいて、Answerクラスに保存するだけでなく、Questionクラスのanswercntに+1する。
(この方法は、質問の評価数をカウントする方法として既に使いました。votesというのがそれです。)

2.質問一覧表示をする時に、表示する質問に対する回答数をカウントして、表示する。
・モデル自体は、変更しない。
・views.pyにおいて、Questionモデルから、最新の10個の質問を取り出して、リスト化する。
・for文を使って、上記質問リストを順に見ていき、当該質問に対するAnswerをカウントし、answercntという変数に格納する。
・表示用のリストに、[[1つ目の質問タイトル, 1つ目の質問内容, 1つ目のanswercnt],[2つ目の質問タイトル, 2つ目の質問内容, 2つ目のanswercnt]、...]という形で格納する。
・上記表示用リストをテンプレートでレンダリングして表示する。
考えてみたコードは、下記のとおりです。

#views.py
def index(request):
    latest_question_list = Question.objects.order_by('-datetime')[:10] #直近10個の質問に絞り込み
    questionIdList = [] #上記10個の質問のIDを格納するリスト
    for question in latest_question_list:
    questionIdList.append(question.id)  
    displayList = [] #レンダリング用のリスト
    for id in questionIdList:
    contentListForQuestion = [] #質問毎に要素を格納するためのリスト
    question = Question.objects.get(id=id) #IDから質問を呼び出す
    contentListForQuestion.append(question.title) #質問タイトルを格納
    contentListForQuestion.append(question.content) #質問内容を格納
    contentListForQuestion.append(question.votes) #質問の評価を格納
    contentListForQuestion.append(question.datetime) #質問日時を格納
    contentListForQuestion.append(len(Answer.objects.filter(question=id)))) #質問に対する回答投稿数を格納
    displayList.append(contentListForQuestion)

上記2つの方法のうち、1つ目は簡単に実装できると思います。しかし、なんとなく、スマートではないと思います。何らかのエラーで、実際の回答数と不整合が生じるリスクもあるので、嫌な感じもします。
そのため、私は、2つ目の方法の方が本来あるべき方法なのではないかと思います。ただ、Questionモデルのデータのみであれば、単純に表示用のリストを作成することができたのに、複数のモデルからデータを引っ張ってくるために、上記のように急に複雑になってしまうので、もっとシンプルな方法が存在するのではないかと思いました。

複数の関連するモデルからデータを引っ張ってきて表示する際の、ベストプラクティスのようなものがあれば、ご教示頂きたいです。
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

teratailは、APIで取得したデータ最大100件の質問を一度に取得できて、そこに回答数を持っているので、2だと質問ごとにAnswersを検索するコストが少し気になりますね。
なので全く確証はありませんが、1の方式を取っていると思います。

1で実装した場合でも、create処理(insert)を複数個所で行わないようにして、そのあとでかならずカウントを更新するようにすれば、不整合が生じるリスクはそれほど致命的ではないように思います。
ただ、回答があった時にインクリメント(プラス1)するのではなく、毎回回答数を取得してアップデートすればより安全でしょう。

もしコストは気にしないとすれば、あとはフレームワーク側でRailsのアソシエーションみたいなことをサポートしていれば、それを使うことでそれほど複雑にならずに済むかもしれません。

Djangoは分からないのでその辺はできるかどうか分かりません。すみません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/09 12:03

    ご回答頂き、ありがとうございます。お礼が遅くなり、申し訳ありません。
    確かに、回答があった時に+1するのではなく、回答の都度、その質問に対する回答数を数えた方が良さそうですね。その方式でやってみようと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる