【问题标题】:How to make visits count seperate for each item如何为每个项目分别计算访问次数
【发布时间】:2021-10-28 16:51:52
【问题描述】:

您好,我正在制作 django 应用程序,我想添加访问计数器功能,但每个项目都是单独的。我认为这将是一个不错的功能。

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['comments'] = Comment.objects.filter(item=self.object)
        context['form'] = CommentCreationForm()
        num_visits = self.request.session.get('num_visits', 0)
        self.request.session['num_visits'] = num_visits + 1
        context['visits'] = num_visits
        return context

【问题讨论】:

  • 通过上述实现,您只需指定此会话中的人访问对象的次数,因此您将其计为每个用户,以及一个用户的访问对其他用户的访问没有影响。
  • 所以我应该修改模型而不是使用普通会话和访问。
  • 在项目模型中添加一个字段,并在每次点击时计数。
  • @MaceiejWojtkowiak:如果你想计算访问者的总数,是的。否则一旦会话结束(例如用户重新启动浏览器),通常该用户的计数将归零,而且其他用户的访问不会产生任何影响
  • 可以分享一下self.object这个商品的型号吗?

标签: django hitcounter visitor-statistic


【解决方案1】:

目前您正在实施的是一个计数器每个会话。实际上,这意味着如果用户在您的页面上启动会话,首先他们将看到零,然后是一个,依此类推。但这只会计算 用户在会话中访问页面的次数。其他用户的访问不会有任何影响。

如果您想跟踪每位用户的总访问次数,则需要让访问数据保持不变。您可以使用额外的模型来做到这一点,例如,每次(注册)用户访问页面时都会创建一条新记录,或者我们可以使用简单的计数器。如果我们想防止多次访问同一个对象时对同一用户进行多次计数,则使用ManyToManyField 对用户更有意义。

选项1:简单IntegerField

一个简单的实现,简单地计算访问次数,因此如果同一用户访问该对象两次,则计算两次,可以使用额外的IntegerField 来计算访问次数,看起来像这样。我们可以为此编写一个抽象模型:

class WithVisitCounter(models.Model):
    visits = models.IntegerField(editable=False, default=0)

    class Meta:
        abstract = True

然后让模型从这里继承:

class BlogPost(WithVisitCounter, models.Model):
    # ⋮

那么我们可以做一个mixin WithVisitCounterMixin:

from django.views.generic.detail import SingleObjectMixin

class WithVisitCounterMixin(SingleObjectMixin):

    def get_object(self, *args, **kwargs):
        obj = super().get_object(*args, **kwargs)
        old_visit = obj.visits
        obj.visits = F('visits') + 1
        obj.save(updated_fields=['visits'])
        obj.visits = old_visit + 1
        return obj

    def get_context_data(self, *args, **kwargs):
        cd = super().get_context_data(*args, **kwargs)
        cd['visits'] = self.object.visits
        return cd

然后我们可以在所有具有SingleObjectMixin 的视图中使用这个Mixin,例如DetailViewUpdateView

class BlogPostDetailView(WithVisitCounterMixin, DetailView):
    # ⋮

这会将访问者的数量作为visits 传递给上下文数据,因此您可以使用{{ visits }}{{ object.visits }}(如果将对象传递给模板)来呈现它。

选项 2:用户模型的 ManyToManyField

第一个选项不考虑多次访问同一对象的用户。这意味着同一用户可以访问该页面二十次,这将被视为二十次独立访问。

在这种情况下,我们可以定义一个抽象模型,为用户添加链接:

from django.conf import settings

class WithVisitCounter(models.Model):
    visitors = models.ManyToManyField(
        to=settings.AUTH_USER_MODEL,
        related_name='%(model_name)s_visits'
    )

    class Meta:
        abstract = True

class BlogPost(WithVisitCounter, models.Model):
    # ⋮

然后我们可以定义一个WithVisitCounterMixin,就像我们为第一个选项所做的那样。在这种情况下,我们将添加一个从对象到登录用户的链接:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.detail import SingleObjectMixin

class WithVisitCounterMixin(SingleObjectMixin):

    def get_object(self, *args, **kwargs):
        obj = super().get_object(*args, **kwargs)
        obj.visitors.add(self.request.user)
        return obj

    def get_context_data(self, *args, **kwargs):
        cd = super().get_context_data(*args, **kwargs)
        cd['visits'] = self.object.visitors.count()
        return cd

对于该单个对象,我们可以通过计算.visitors 的记录数来获取访问者self.object

因此,我们也可以在 DetailViewUpdateView 中使用该 mixin:

class BlogPostDetailView(WithVisitCounterMixin, DetailView):
    # ⋮

然后我们可以再次使用{{ visits }} 作为该项目的访问者数量。

【讨论】:

  • 我们可以将这些函数也传递给 Rest API 吗?
猜你喜欢
  • 2011-10-16
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 2014-03-18
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2012-07-23
相关资源
最近更新 更多