models.py
1.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from django.db import models
from django.core.cache import cache
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
class Hit(models.Model):
created = models.DateField(auto_now_add=True, db_index=True)
updated = models.DateField(auto_now=True, db_index=True)
hits = models.PositiveIntegerField(default=0)
content_type = models.ForeignKey(ContentType)
object_pk = models.CharField(max_length=256)
class Meta:
unique_together = ('content_type', 'object_pk')
class HitCountModelMixin(object):
@property
def hits(self):
content_type = ContentType.objects.get_for_model(self.__class__,
for_concrete_model=False)
try:
hit = Hit.objects.get(content_type=content_type,
object_pk=self.pk)
except Hit.DoesNotExist:
return 0
return hit.hits
def hit(self, request=None):
content_type = ContentType.objects.get_for_model(self.__class__)
# Here we cache the user's IP to ensure that the same
# IP won't hit the same page again for while
if request:
ip_addr = request.META.get('REMOTE_ADDR')
cache_key = u'page_hits-{}-{}-{}'.format(ip_addr,
content_type, self.pk)
duplicate = cache.get(cache_key)
if duplicate:
return
cache.set(cache_key, True)
# Everything ok, so just increment the page count
hit_pk = Hit.objects.get_or_create(content_type=content_type,
object_pk=self.pk)[0].pk
# Using this way instead of hits += 1 forces django to
# call the UPDATE directly in the database avoiding
# cuncurrency problems
Hit.objects.filter(pk=hit_pk).update(hits=models.F("hits") + 1)