Django页面访问计数器并发问题

2 投票
3 回答
3075 浏览
提问于 2025-04-17 00:31

我是一名Django新手。为了大学的网页编程课程,我正在做一个简单的访问计数器。我创建了一个叫做HitCount的类:

from django.db import models

# Create your models here.

class HitCount(models.Model):
    count = models.IntegerField()

然后我在视图文件中使用了这段代码:

def index(request):

    #try getting a hitcounter, if there is none, create one
    try:
        hc = HitCount.objects.get(pk=1)
    except: 
        hc = HitCount(count=0)
        hc.save()
        pass

    #get a queryset containing our counter
    hc = HitCount.objects.filter(pk=1)
    #increment its count and update it in db
    hc.update(count=F('count')+1)
    #ATM hc is a queryset, so hc.count will just return how many
    #counters are in the queryset (1). So we have to get the
    #actual counter object
    hc = HitCount.objects.get(pk=1)
    #and return its count
    return render_to_response('hitcount/index.html', {'count': hc.count})

这是我的index.html文件:

<p>{{count}}</p>

看起来这个功能运行得很好,但我有一些疑问:

  • 这样做合理吗?增加计数的代码真的应该放在视图文件里吗?还是应该把它放到类里的一个方法中?
  • 这样做是安全的吗?我需要使用某种锁吗?作业的一部分是让计数器在并发情况下也能安全工作。我使用的是SQLite,它支持事务,所以我觉得应该没问题,但我可能漏掉了什么。

3 个回答

0

你可以为每次点击创建一个新的数据库记录,然后用 HitCount.objects.count() 来获取总的点击次数。

2

在Python中,可以使用以下方法来实现锁定:

lock = Lock()
lock.acquire()
try:
    ... access shared resource
finally:
    lock.release() # release lock, no matter what

不过要注意,这种方法在多服务器环境下并不安全。

你还可以创建一个更灵活的“日志记录”方案,把每次访问记录为数据库中的一行,并附上相关信息,这样就可以在特定的日期范围内进行统计或查询。

3

虽然这个话题有点偏,但你应该在你的try/except代码中捕捉到HitCount.DoesNotExist,因为你只想在HitCount对象还不存在的时候执行except中的代码。

如果可以的话,你可以考虑使用Redis(或者其他的键值存储)来做你的点击计数器。

Redis提供了一个叫做INCR的方法,可以自动把一个值加1。这非常快,非常适合用来做点击计数器。你只需要创建一个和页面相关的键,然后就可以把它加1。

使用中间件类来跟踪页面点击可能会更合理。这样比在每个视图中都添加代码要简单得多。如果你需要在每个页面上显示这个计数,可以使用上下文处理器更多信息)把页面的点击计数加入上下文中。这样可以减少代码重复。

编辑

我最开始没注意到这是一个大学项目,所以这可能对你来说有点过于复杂。不过,如果你将来要为生产环境构建一个点击计数器,我会推荐这种方法。你仍然可以使用中间件/上下文处理器以一种简洁的方式来进行点击计数和数据获取。

撰写回答