Django博客views_count刷新时递增2次的问题求助
博客详情页浏览量刷新递增两次的问题解决
问题描述
作为Django初学者,我搭建了带有浏览量统计、分类、标签功能的博客详情页,但刷新页面时views_count字段每次会递增2次,期望实现每次刷新仅递增1次。
相关代码
Post模型
class Post(models.Model): title = models.CharField(max_length=250) content = RichTextUploadingField() post_date = models.DateTimeField(auto_now=True) slug = models.SlugField(max_length=200, unique=True) image = models.ImageField(null=True, blank=True, upload_to="images/") tagss = models.ManyToManyField(Tags, blank=True, related_name='post') Categorys = models.ManyToManyField(Category, blank=True, related_name='post') views_count = models.IntegerField(default=0, null=True, blank=True) def __str__(self): return self.title
视图函数
def post_page(request, slug): post = Post.objects.get(slug = slug) post.views_count = post.views_count + 1 post.save() print("views:", post.views_count ) cats = Category.objects.all() tags = Tags.objects.all() random_items = list(Post.objects.all().order_by('?')[:2]) related_posts = list( Post.objects.filter( Q(tagss__name__in=[tag.name for tag in post.tagss.all()]) | Q(Categorys__name__in=[Category.name for Category in post.Categorys.all()]) ).distinct() ) recent_posts = Post.objects.all().order_by('-id')[:4] context = {'post': post, 'cats': cats, 'tags': tags, 'recent_posts': recent_posts, 'random_blog': random_items, 'related_posts': related_posts} return render(request, 'blog/Blog_details.html', context)
URL配置
from . import views from django.urls import path urlpatterns = [ path('blog', views.blogs, name='blog'), path('blog/<slug:slug>', views.post_page, name= 'blog_page') ]
解决方案
1. 使用原子更新避免竞态条件
当前代码直接修改内存中的post对象再保存,存在竞态条件,且易受重复请求影响。改用Django的F()表达式直接在数据库层面做原子更新,确保计数操作仅执行一次:
修改视图中的浏览量统计部分:
from django.db.models import F def post_page(request, slug): # 原子更新浏览量,直接在数据库层面操作 Post.objects.filter(slug=slug).update(views_count=F('views_count') + 1) # 重新获取更新后的文章数据 post = Post.objects.get(slug=slug) # 剩余代码保持不变 cats = Category.objects.all() tags = Tags.objects.all() random_items = list(Post.objects.all().order_by('?')[:2]) related_posts = list( Post.objects.filter( Q(tagss__name__in=[tag.name for tag in post.tagss.all()]) | Q(Categorys__name__in=[Category.name for Category in post.Categorys.all()]) ).distinct() ) recent_posts = Post.objects.all().order_by('-id')[:4] context = {'post': post, 'cats': cats, 'tags': tags, 'recent_posts': recent_posts, 'random_blog': random_items, 'related_posts': related_posts} return render(request, 'blog/Blog_details.html', context)
2. 排除同一用户重复刷新的计数
如果希望同一用户在一段时间内刷新页面不重复计数,可以利用Django的Session记录用户已浏览过的文章:
from django.db.models import F def post_page(request, slug): post = Post.objects.get(slug=slug) # 生成唯一Session键,标记用户是否已浏览该文章 session_key = f'viewed_post_{post.id}' if not request.session.get(session_key, False): # 仅当用户未浏览过时更新计数 Post.objects.filter(slug=slug).update(views_count=F('views_count') + 1) # 标记该文章已浏览,24小时内不再重复计数 request.session[session_key] = True request.session.set_expiry(86400) # 重新获取更新后的数据(若计数已更新) post.refresh_from_db() # 剩余代码保持不变 cats = Category.objects.all() tags = Tags.objects.all() random_items = list(Post.objects.all().order_by('?')[:2]) related_posts = list( Post.objects.filter( Q(tagss__name__in=[tag.name for tag in post.tagss.all()]) | Q(Categorys__name__in=[Category.name for Category in post.Categorys.all()]) ).distinct() ) recent_posts = Post.objects.all().order_by('-id')[:4] context = {'post': post, 'cats': cats, 'tags': tags, 'recent_posts': recent_posts, 'random_blog': random_items, 'related_posts': related_posts} return render(request, 'blog/Blog_details.html', context)
3. 排查重复请求原因
若上述方法无效,检查是否存在以下情况:
- 页面中存在无效资源引用(如图片路径错误),导致浏览器重复请求当前页面
- URL配置存在重定向问题(如带斜杠和不带斜杠的URL触发两次请求),可将URL改为带结尾斜杠的格式:
urlpatterns = [ path('blog/', views.blogs, name='blog'), path('blog/<slug:slug>/', views.post_page, name= 'blog_page') ] - 本地开发时
DEBUG=True模式的自动重载可能引发异常请求,可尝试关闭调试模式测试。
内容的提问来源于stack exchange,提问作者Emad Younan
相关产品推荐
相关产品推荐

