This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

[Day 25]DjangoのAPIとAjax通信する「いいねボタン」を作成する

Last updated at Posted at 2021-02-02

February 1, 2021
←前回:Day 24 テンプレートのフィルターを使う

「Djangoを学びたい」とのことでありましたら[Day 1]Djangoの開発環境から読むことをおすすめします。

はじめに

今回はDjangoで作られたAPIにjavascriptでAjax通信する処理を見ていきたいと思います。

いいねボタンを作るための準備

いいねボタンがどんなものかは説明不要だと思いますが、想定を簡単に説明しておきます。
ユーザーがいいねボタンを押すと1POINT加点されリアルタイムで数字が変化します。
連打防止はjavascriptおよびIPアドレスで判定します。
これを実装するにあたりvoteモデルを用意します。

thread/models.py

class VoteManager(models.Manager):
    def create_vote(self, ip_address, comment_id):
        vote = self.model(
            ip_address=ip_address,
            comment_id = comment_id
        )
        try:
            vote.save()
        except:
            return False
        return True

class Vote(models.Model):
    comment = models.ForeignKey(
        Comment,
        on_delete=models.CASCADE,
        null=True,
    )
    ip_address = models.CharField(
        'IPアドレス',
        max_length=50,
    )

    objects = VoteManager()

    def __str__(self):
        return '{}-{}'.format(self.comment.topic.title, self.comment.no)

ここはモデル作成の部分で説明済みですので特に問題ないと思います。
モデルの準備が出来たらマイグレーションをしましょう。もう大丈夫ですね。


(venv)$ ./manage.py makemigrations
(venv)$ ./manage.py migrate

voteの数を数えるようにthread/views.pyを変更しましょう。

thread/views.py(一部抜粋)

  class TopicAndCommentView(FormView):
      template_name = 'thread/detail_topic.html'
      form_class = CommentModelForm

      def form_valid(self, form):
          # comment = form.save(commit=False)
          # comment.topic = Topic.objects.get(id=self.kwargs['pk'])
          # comment.no = Comment.objects.filter(topic=self.kwargs['pk']).count() + 1
          # comment.save()
          Comment.objects.create_comment(
              user_name=form.cleaned_data['user_name'],
              message=form.cleaned_data['message'],
              topic_id=self.kwargs['pk'],
          )
          return super().form_valid(form)

      def get_success_url(self):
          return reverse_lazy('thread:topic', kwargs={'pk': self.kwargs['pk']})

      def get_context_data(self):
          ctx = super().get_context_data()
          ctx['topic'] = Topic.objects.get(id=self.kwargs['pk'])
-         ctx['comment_list'] = Comment.objects.filter(
-                 topic_id=self.kwargs['pk']).order_by('no')
+         ctx['comment_list'] = Comment.objects.filter(
+                 topic_id=self.kwargs['pk']).annotate(vote_count=Count('vote')).order_by('no')
          return ctx

特に説明は不要かと思います。
annotateで各コメントが参照しているVoteモデルの数を数えて追加しています。
このvote_countが投票されたポイントとなります。

テンプレート側の準備

いいねボタンのUIを準備しましょう。templates/thread/detail_topic.htmlを修正します。

とまあ、ここで一旦ブラウザを確認敷いてみますと、エラー発生していました。
原因を調べると、thread/models.pyのVoteクラス内でCommentが出てくるのですが、それが定義されていないというエラーが出てしまいます。

なぜでしょう?わからないです。。。
以前コメント機能を作成しようと試みてできなかったのですが、修正してなんとかできるようになりました。
ブサイクなコメント機能かもしれませんが、コメントできるようになりました。

今回は「いいねボタン」のUIだけで我慢します。
直せる時にまた直します。

終わりに

最近、僕の中でZoom会議の回数が多いです。
Zoom会議は外に出なくて済むのでとても楽です。
仕事の内容や業務内容はいつでもできてしまいますね。
なので、これからは直接会わないといけない趣味の時間が大切になってくるのではないのでしょうか。

それではまたまた

←前回:Day 24 テンプレートのフィルターを使う
→次回:Day 26 検索機能の作成

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up