【问题标题】:Best way to monitor number of views on a blog post in Django在 Django 中监控博客文章的查看次数的最佳方法
【发布时间】:2021-02-20 07:40:42
【问题描述】:

我正在开发一个博客网络应用程序,我想监控一篇文章的浏览量。我决定使用帖子详细信息视图来计算。为了防止计数器为特定用户增加,我将只允许登录用户计数,并且用户只能计数一次。

这是我的帖子模型

class Post(models.Model):
    title = models.CharField(max_length=150)
    content = models.TextField(max_length=3000, null=True, blank=True)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    viewers = models.TextField(default="", null=True, blank=True)
    numViews = models.IntegerField(default=0)

    def __str__(self):
        return self.title

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

我基本上使用字段“viewers”来跟踪已统计的用户,并使用“numviews”作为计数器。

我的views.py函数

class PostDetailView(DetailView):
    model = Post

    def get(self, request, *args, **kwargs):
        # increment post views whenever request is made
        postObject = self.get_object()
        user = request.user

        if postObject.viewers == None:
            postObject.viewers = ""
            postObject.save()

        if user.is_authenticated and user.username not in postObject.viewers:
            # increment 
            postObject.numViews += 1
            postObject.save()
            # add username to viewers list
            postObject.viewers+=user.username
            postObject.save()
            
        return super().get(request, *args, **kwargs)

在视图函数中,我正在检查用户名是否已附加到查看器字符串中,否则附加它并增加计数器。 有没有更有效的方法来做到这一点?如果博客获得成千上万的浏览量,那将是一串很长的用户名。

【问题讨论】:

  • 您通过哪个variable 访问post viewsquerysetcreated ?

标签: python django blogs


【解决方案1】:

如果博客获得成千上万的浏览量,它将是一串很长的用户名。

这不仅效率低下,而且可能导致错误的结果。如果您有三个用户foobarfoobar,那么如果foo 访问该页面,bar 访问该页面,那么如果foobar 访问该页面,他们的视图将不会被纳入帐户。

另一个问题是这里可能存在竞争条件:如果两个用户几乎同时访问同一个帖子,那么数据库可能最终只更新的对象>一个用户,因此就像其他用户从未访问过该页面一样。

您通常通过ManyToManyField [Django-doc] 确定谁查看了帖子:

from django.conf import settings

class Post(models.Model):
    title = models.CharField(max_length=150)
    content = models.TextField(max_length=3000, null=True, blank=True)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    viewers = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='viewed_posts'
        editable=False
    )

    def __str__(self):
        return self.title

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

那么我们可以将视图实现为:

from django.db.models import Count

class PostDetailView(DetailView):
    model = Post
    queryset = Post.objects.annotate(
        num_views=Count('viewers')
    )

    def get_context_data(self, *args, **kwargs):
        if self.request.user.is_authenticated:
            __, created = Post.viewers.through.objects.get_or_create(
                post=self.object,
                user=self.request.user
            )
            if created:
                self.object.num_views += 1
        return super().get_context_data(*args, **kwargs)

【讨论】:

  • 不需要按照documentation使用get_or_create "添加第二次就可以了,不会重复关系:"。您可以不假思索地添加。
  • @AbdulAzizBarkat:是的,但我们需要知道是否应该增加 num_views :) 这是包含它的唯一原因
  • 你是对的,没想到这一点。 :)
  • 可以在function based views做吗?
  • @Progam:是的,只需在函数中添加逻辑,self.object 就是您获取的对象。但是由于有很多可重用的逻辑,基于类的视图通常更好地混合在逻辑中。
【解决方案2】:

我用@Willem Van Onsem 修改了我的代码,它似乎工作正常。在帖子详细信息视图中,唯一的修正是 self.user -> self.request.user 。也可以通过 ((post.viewers.count}} 在 html 模板中的帖子对象中访问查看者的数量,在详细视图模板中作为 {{object.num_views}}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 2022-01-26
    • 2011-12-28
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2011-09-13
    相关资源
    最近更新 更多