2

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

1 回答 1

2

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

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

选项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

然后我们可以Mixin在所有有SingleObjectMixinaDetailView和 an 的视图中使用它UpdateView

class BlogPostDetailView(WithVisitCounterMixin, DetailView):
    # ⋮

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

选项2:AManyToManyField到用户模型

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

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

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

DetailView因此,我们也可以在 a or中使用该 mixin UpdateView

class BlogPostDetailView(WithVisitCounterMixin, DetailView):
    # ⋮

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

于 2021-08-29T18:37:21.920 回答