在 Django 中监控博客 post 浏览量的最佳方法
Best way to monitor number of views on a blog post in Django
我正在开发一个博客网络应用程序,我想监控 post 的浏览量。我决定使用 post 详细视图来计数。为了防止特定用户的计数器增加,我将只允许登录用户计数,并且一个用户只能计数一次。
这是我的post模型
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' 作为计数器。
我的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)
在视图函数中,我正在检查用户名是否已附加到观众字符串,否则附加它并增加计数器。
有没有更有效的方法来做到这一点?在博客获得数千次浏览的情况下,这将是一串很长的用户名。
In the case the blog gets thousands of views, it is going to be a very long string of usernames.
不仅效率低下,而且会导致错误的结果。如果你有三个用户foo
、bar
和foobar
,那么如果foo
访问了页面,bar
访问了页面,那么如果foobar
访问页面,他们的观点将不被考虑。
另一个问题是这里可能存在竞争条件:如果两个用户大约同时访问同一个post,则可能是数据库最终只为 一个 用户更新对象,因此就像其他用户从未访问过该页面一样。
通常您通过 ManyToManyField
[Django-doc]:
来确定谁查看了 post
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.<b>ManyToManyField(</b>
settings.AUTH_USER_MODEL,
related_name='viewed_posts'
editable=False
<b>)</b>
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(
<b>num_views=Count('viewers')</b>
)
def get_context_data(self, *args, **kwargs):
if self.request.user.is_authenticated:
__, created = Post.viewers.through.objects<b>.get_or_create(</b>
post=self.object,
user=self.request.user
<b>)</b>
if created:
self.object.num_views += 1
return super().get_context_data(*args, **kwargs)
我用@Willem Van Onsem 修改了我的代码,它似乎工作正常。唯一的修正是 self.user -> self.request.user 在 post 详细视图中。此外,可以通过 ((post.viewers.count}} 在 html 模板中访问 post 对象中的查看者数量,在详细视图模板中作为 {{object.num_views}}
我正在开发一个博客网络应用程序,我想监控 post 的浏览量。我决定使用 post 详细视图来计数。为了防止特定用户的计数器增加,我将只允许登录用户计数,并且一个用户只能计数一次。
这是我的post模型
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' 作为计数器。
我的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)
在视图函数中,我正在检查用户名是否已附加到观众字符串,否则附加它并增加计数器。 有没有更有效的方法来做到这一点?在博客获得数千次浏览的情况下,这将是一串很长的用户名。
In the case the blog gets thousands of views, it is going to be a very long string of usernames.
不仅效率低下,而且会导致错误的结果。如果你有三个用户foo
、bar
和foobar
,那么如果foo
访问了页面,bar
访问了页面,那么如果foobar
访问页面,他们的观点将不被考虑。
另一个问题是这里可能存在竞争条件:如果两个用户大约同时访问同一个post,则可能是数据库最终只为 一个 用户更新对象,因此就像其他用户从未访问过该页面一样。
通常您通过 ManyToManyField
[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.<b>ManyToManyField(</b>
settings.AUTH_USER_MODEL,
related_name='viewed_posts'
editable=False
<b>)</b>
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(
<b>num_views=Count('viewers')</b>
)
def get_context_data(self, *args, **kwargs):
if self.request.user.is_authenticated:
__, created = Post.viewers.through.objects<b>.get_or_create(</b>
post=self.object,
user=self.request.user
<b>)</b>
if created:
self.object.num_views += 1
return super().get_context_data(*args, **kwargs)
我用@Willem Van Onsem 修改了我的代码,它似乎工作正常。唯一的修正是 self.user -> self.request.user 在 post 详细视图中。此外,可以通过 ((post.viewers.count}} 在 html 模板中访问 post 对象中的查看者数量,在详细视图模板中作为 {{object.num_views}}