You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:04:50