目前您正在实施的是一个计数器每个会话。实际上,这意味着如果用户在您的页面上启动会话,首先他们将看到零,然后是一个,依此类推。但这只会计算 用户在会话中访问页面的次数。其他用户的访问不会有任何影响。
如果您想跟踪每位用户的总访问次数,则需要让访问数据保持不变。您可以使用额外的模型来做到这一点,例如,每次(注册)用户访问页面时都会创建一条新记录,或者我们可以使用简单的计数器。如果我们想防止多次访问同一个对象时对同一用户进行多次计数,则使用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,例如DetailView 和UpdateView:
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。
因此,我们也可以在 DetailView 或 UpdateView 中使用该 mixin:
class BlogPostDetailView(WithVisitCounterMixin, DetailView):
# ⋮
然后我们可以再次使用{{ visits }} 作为该项目的访问者数量。