<blockquote>
<p>In the case the blog gets thousands of views, it is going to be a very long string of usernames.</p>
</blockquote>
<p>它不仅效率低下,而且可能导致错误的结果。如果您有三个用户<code>foo</code>、<code>bar</code>和<code>foobar</code>,那么如果<code>foo</code>访问页面,并且<code>bar</code>访问页面,那么如果<code>foobar</code>访问页面,他们的视图将不被考虑</p>
<p>另一个问题是这里可能存在<em>竞争条件</em>:如果两个用户几乎同时访问同一个帖子,则数据库可能只更新一个<em>用户的对象,因此就像另一个用户从未访问过页面一样</p>
<p>通常,您可以通过<a href="https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField" rel="nofollow noreferrer"><strong>^{<cd7>}</strong> [Django-doc]</a>确定谁查看了帖子:</p>
<pre><code>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})</code></pre>
<p>然后,我们可以将该视图实现为:</p>
<pre><code>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.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)</code></pre>