在Django中监控博客文章浏览量的最佳方法

2024-10-02 20:32:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个博客webapp,我想监控一篇文章的浏览量。我已经决定使用PostDetail视图进行计数。为了防止特定用户的计数器递增,我将只允许记录的用户计数,并且一个用户只能计数一次

这是我的贴身模特

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”作为计数器

My 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)

在views函数中,我检查用户名是否已经附加到viewers字符串中,否则附加用户名并递增计数器。 有没有更有效的方法?如果博客获得数千个视图,那么它将是一个非常长的用户名字符串


Tags: 用户selftruedefaultgetreturnmodelsrequest
2条回答

我用@Willem Van Onsem修改了我的代码,它似乎工作正常。仅对self.user->;post详细信息视图中的self.request.user。另外,可以通过((post.viewers.count}})访问html模板中的一个post对象,并在详细视图模板中作为{object.num_views}访问该对象

In the case the blog gets thousands of views, it is going to be a very long string of usernames.

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

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

通常,您可以通过^{} [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.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)

相关问题 更多 >