Django页面访问计数器并发问题
我是一名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。
使用中间件类来跟踪页面点击可能会更合理。这样比在每个视图中都添加代码要简单得多。如果你需要在每个页面上显示这个计数,可以使用上下文处理器(更多信息)把页面的点击计数加入上下文中。这样可以减少代码重复。
编辑
我最开始没注意到这是一个大学项目,所以这可能对你来说有点过于复杂。不过,如果你将来要为生产环境构建一个点击计数器,我会推荐这种方法。你仍然可以使用中间件/上下文处理器以一种简洁的方式来进行点击计数和数据获取。