【问题标题】:Counting problem in django blog: using django ajaxdjango 博客中的计数问题:使用 django ajax
【发布时间】:2020-08-19 05:15:11
【问题描述】:

我使用 ajax 为我的 django 博客创建了一个赞按钮,但我收到一个错误,它计数不正确,起初它的 0 就像我点击的帖子中的一样工作 1 就像出现了不同的按钮但是当我再次点击不喜欢和喜欢时,它会给出 2 个喜欢,有时当我不喜欢它时会显示 -1,就像我认为它的 jQuery 问题我不是 jQuery 专家

jQuery

$(document).ready(function() {
  function updateText(btn, newCount, verb) {
      btn.text(newCount + " " + verb)
  }

  $(".like-btn").click(function(e) {
    e.preventDefault()
    var this_ = $(this)
    var likeUrl = this_.attr("data-href")
    var likeCount = parseInt(this_.attr("data-likes")) |0
    var addLike = likeCount + 1
    var removeLike = likeCount - 1
    if (likeUrl){
       $.ajax({
        url: likeUrl,
        method: "GET",
        data: {},
        success: function(data){
          console.log(data)
          var newLikes;
          if (data.liked){
              updateText(this_, addLike, "Unlike")
          } else {
              updateText(this_, removeLike, "Like")
              // remove one like
          }

        }, error: function(error){
          console.log(error)
          console.log("error")
        }
      })
    }
  })
})

post.html

 {% if user not in post.likes.all %}
           <p><a class='like-btn' data-href='{{ object.get_api_like_url }}'
                 data-likes='{{ object.likes.all.count }}' href='{{ object.get_like_url }}'>
               {{ object.likes.all.count }} Like</a></p>
  {% else %}
            <p><a class='like-btn' data-href='{{ object.get_api_like_url }}'
                 data-likes='{{ object.likes.all.count }}' href='{{ object.get_like_url }}'>
                {{ object.likes.all.count }} Unlike</a></p>
  {% endif %}

views.py

class PostLikeToggle(RedirectView):

      def get_redirect_url(self, *args, **kwargs):
      obj = get_object_or_404(Post, pk=kwargs['pk'])
      url_ = obj.get_absolute_url()
      user = self.request.user
      if user.is_authenticated:
         if user in obj.likes.all():
            obj.likes.remove(user)
         else:
            obj.likes.add(user)
      return url_

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User

class PostLikeApiToggle(APIView):


    authentication_classes = [authentication.SessionAuthentication]
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, pk, format=None):

        obj = get_object_or_404(Post, pk=pk)
        url_ = obj.get_absolute_url()
        user = self.request.user
        updated = False
        liked =False
        if user.is_authenticated:
           if user in obj.likes.all():
              liked = False
              obj.likes.remove(user)
           else:
               liked = True
               obj.likes.add(user)
        updated = True
        data = {
               "updated":updated,
                "liked":liked
               }

       return Response(data)

models.py

class Post(models.Model):

     title = models.CharField(max_length=200)
     author = models.ForeignKey(User,on_delete=models.CASCADE)
     likes =models.ManyToManyField(User,blank=True,related_name='post_likes')
     content = models.TextField()
     img = models.ImageField(upload_to='pics',blank=True)
     time = models.DateTimeField(default=timezone.now)

     def __str__(self):
       return self.title

    def get_absolute_url(self):
        return reverse('LoveTravel-Details', kwargs={'pk': self.pk})

    def get_like_url(self):
        return reverse('Like-Toggle', kwargs={'pk':self.pk})

   def get_api_like_url(self):
       return reverse('Like-Api-Toggle', kwargs={'pk':self.pk})

【问题讨论】:

    标签: javascript jquery django django-rest-framework django-views


    【解决方案1】:

    您的问题很可能是竞争条件。这意味着当单击同一个按钮两次时,您的代码尚未更新数据库以反映 +1/-1,因此下一次单击将添加/删除额外的数字。

    有几种方法可以解决这个问题,例如使用 F 表达式或内联 JS 计数,但最好的方法可能是在你的 JS 中添加一个标志以禁止喜欢/不喜欢,直到你当前的 JS 请求被处理.这可以通过在已单击按钮时禁用按钮,然后在 AJAX 响应完成时再次启用它们(使用 complete AJAX 回调)来轻松完成。

    您可以进行的其他一些改进:

    1) 删除多余的if user.is_authenticated(因为看起来您已经在permission_classes 中定义了该要求

    2) 使用obj.likes.filter(likes=user) 代替if user in obj.likes.all():,然后根据此重构条件以使其工作

    【讨论】:

      【解决方案2】:

      让您的 API 简单地返回实际的新点赞数可能会解决 +2 / -1 问题。

      • 我通过翻转 if(likeUrl) 检查取消了 javascript 函数的嵌套。
      • addLike/removeLike 变量已替换为 data.n_likes 属性。
      • 由于此操作会修改服务器上的状态,因此最好将其作为 POST 操作发送而不是 GET。
      function updateText(btn, newCount, verb) {
        btn.text(newCount + " " + verb);
      }
      
      $(document).ready(function() {
        $(".like-btn").click(function(e) {
          e.preventDefault();
          var this_ = $(this);
          var likeUrl = this_.attr("data-href");
          if (!likeUrl) return;
          $.ajax({
            url: likeUrl,
            method: "POST",
            data: {},
            success: function(data) {
              console.log(data);
              var newLikes;
              if (data.liked) {
                updateText(this_, data.n_likes, "Unlike");
              } else {
                updateText(this_, data.n_likes, "Like");
              }
            },
            error: function(error) {
              console.log(error);
              console.log("error");
            },
          });
        });
      });
      

      在后端——你不需要 DRF,但因为它已经存在了——

      • 使用def post 代替def get
      • 无需检查用户是否通过身份验证;权限类会这样做
      • 在响应中返回点赞数(并删除不必要的updated)。
      class PostLikeApiToggle(APIView):
      
          authentication_classes = [authentication.SessionAuthentication]
          permission_classes = [permissions.IsAuthenticated]
      
          def post(self, request, pk, format=None):
              obj = get_object_or_404(Post, pk=pk)
              url_ = obj.get_absolute_url()
              user = self.request.user
              liked = False
              if obj.likes.filter(id=user.id).exists():
                  obj.likes.remove(user)
              else:
                  obj.likes.add(user)
                  liked = True
      
              return Response({
                  "liked": liked,
                  "n_likes": obj.likes.count(),
              })
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2023-03-26
        • 1970-01-01
        • 2012-03-30
        • 1970-01-01
        • 2011-12-15
        • 2023-02-13
        • 2021-04-16
        • 2017-07-03
        • 2010-11-11
        相关资源
        最近更新 更多