开发者

Django page hit counter concurrency

Im a django newbie. Im making a crude hit counter as an assignment for a course in web programming at Uni. I made a class HitCount:

from django.db import models

# Create your models here.

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

And then I use this code in the views file:

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})

This is my index.html file:

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

This seems to work just fine, but I wonder:

  • Is this a reasonable way of doing this? Should the code for incrementation really reside in the views file? Or should I move it into a method i开发者_运维问答n the class?
  • Is this concurrency safe or do I need to use some kind of lock? Part of the assignment is making the counter concurrency safe. I use SQLite, which uses transactions, so I figured it should be all right, but I may be missing something.


Off topic, but you should be catching HitCount.DoesNotExist in your try/except, since you really only want to execute the code in the except if the HitCount object doesn't exist yet.

If it's possible, you might want to look at something like Redis (or another key/val store) to do your hit counter.

Redis provides a method called INCR that will automatically increment a value by 1. It's super fast and a great solution for a hit counter like this. All you need to do is make a key that is related to the page and you can increment that by +1.

It might also make more sense to use a middleware class to track page hits. Much easier than adding it to every view. If you need to display this count on every page, you can use a context processor (more info) to add the page's hit count into the context. There will be less code repetition this way.

Edit

I initially missed that this was for a Uni project, so this might be heavily over engineering for what you need. However, if you were to ever build a hit counter for a production environment, this is what I'd recommend. You can still use the middleware/context processors to do the hit counts/retrieval in a DRY manner.


Locking is possible in python using the following:

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

Keep in mind that method is not safe in a multi-server environment though.

You could also create a more extensible 'logging' solution that tracks each hit as a row in the db with associated info, and then be able to count/query even at a particular date range.


You could create a new database row for each hit and call HitCount.objects.count() to get the count.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜