如何为每个项目单独计算访问次数

How to make visits count seperate for each item

您好,我正在制作 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

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

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

选项 1:简单 IntegerField

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

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

    class Meta:
        <strong>abstract = True</strong>

然后让模型继承这个:

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<b>.visits = F('visits') + 1</b>
        obj.save(<b>updated_fields=['visits']</b>)
        obj.visits = old_visit + 1
        return obj

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

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

class BlogPostDetailView(<strong>WithVisitCounterMixin,</strong> DetailView):
    # ⋮

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

选项 2:A ManyToManyField 给用户模型

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

在这种情况下,我们可以定义一个抽象模型,它将向用户添加 links,其中:

from django.conf import settings

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

    class Meta:
        <strong>abstract = True</strong>

class BlogPost(<strong>WithVisitCounter,</strong> models.Model):
    # ⋮

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

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<strong>.visitors.add(</strong>self.request.user<strong>)</strong>
        return obj

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

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

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

class BlogPostDetailView(WithVisitCounterMixin, DetailView):
    # ⋮

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