Commit 55eab2f1cdaf7b043fe47392f8228031fedf792e

Authored by Sergio Oliveira
1 parent c594339b

Adding missing directory. Updates #21

src/hitcount/__init__.py 0 → 100644
src/hitcount/admin.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
... ...
src/hitcount/migrations/0001_initial.py 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +# -*- coding: utf-8 -*-
  2 +import datetime
  3 +from south.db import db
  4 +from south.v2 import SchemaMigration
  5 +from django.db import models
  6 +
  7 +
  8 +class Migration(SchemaMigration):
  9 +
  10 + def forwards(self, orm):
  11 + # Adding model 'Hit'
  12 + db.create_table(u'hitcount_hit', (
  13 + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
  14 + ('created', self.gf('django.db.models.fields.DateField')(auto_now_add=True, db_index=True, blank=True)),
  15 + ('updated', self.gf('django.db.models.fields.DateField')(auto_now=True, db_index=True, blank=True)),
  16 + ('hits', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
  17 + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
  18 + ('object_pk', self.gf('django.db.models.fields.CharField')(max_length=256)),
  19 + ))
  20 + db.send_create_signal(u'hitcount', ['Hit'])
  21 +
  22 + # Adding unique constraint on 'Hit', fields ['content_type', 'object_pk']
  23 + db.create_unique(u'hitcount_hit', ['content_type_id', 'object_pk'])
  24 +
  25 +
  26 + def backwards(self, orm):
  27 + # Removing unique constraint on 'Hit', fields ['content_type', 'object_pk']
  28 + db.delete_unique(u'hitcount_hit', ['content_type_id', 'object_pk'])
  29 +
  30 + # Deleting model 'Hit'
  31 + db.delete_table(u'hitcount_hit')
  32 +
  33 +
  34 + models = {
  35 + u'contenttypes.contenttype': {
  36 + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
  37 + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  38 + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  39 + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
  40 + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
  41 + },
  42 + u'hitcount.hit': {
  43 + 'Meta': {'unique_together': "(('content_type', 'object_pk'),)", 'object_name': 'Hit'},
  44 + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
  45 + 'created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
  46 + 'hits': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
  47 + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
  48 + 'object_pk': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
  49 + 'updated': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'})
  50 + }
  51 + }
  52 +
  53 + complete_apps = ['hitcount']
0 54 \ No newline at end of file
... ...
src/hitcount/migrations/__init__.py 0 → 100644
src/hitcount/models.py 0 → 100644
... ... @@ -0,0 +1,51 @@
  1 +
  2 +from django.db import models
  3 +from django.core.cache import cache
  4 +from django.contrib.contenttypes import generic
  5 +from django.contrib.contenttypes.models import ContentType
  6 +
  7 +
  8 +class Hit(models.Model):
  9 + created = models.DateField(auto_now_add=True, db_index=True)
  10 + updated = models.DateField(auto_now=True, db_index=True)
  11 + hits = models.PositiveIntegerField(default=0)
  12 + content_type = models.ForeignKey(ContentType)
  13 + object_pk = models.CharField(max_length=256)
  14 +
  15 + class Meta:
  16 + unique_together = ('content_type', 'object_pk')
  17 +
  18 +
  19 +class HitCountModelMixin(object):
  20 +
  21 + @property
  22 + def hits(self):
  23 + content_type = ContentType.objects.get_for_model(self.__class__,
  24 + for_concrete_model=False)
  25 + try:
  26 + hit = Hit.objects.get(content_type=content_type,
  27 + object_pk=self.pk)
  28 + except Hit.DoesNotExist:
  29 + return 0
  30 +
  31 + return hit.hits
  32 +
  33 + def hit(self, request=None):
  34 + content_type = ContentType.objects.get_for_model(self.__class__)
  35 +
  36 + # Here we cache the user's IP to ensure that the same
  37 + # IP won't hit the same page again for while
  38 + if request:
  39 + ip_addr = request.META.get('REMOTE_ADDR')
  40 + cache_key = u'page_hits-{}-{}-{}'.format(ip_addr,
  41 + content_type, self.pk)
  42 + duplicate = cache.get(cache_key)
  43 + if duplicate:
  44 + return
  45 + cache.set(cache_key, True)
  46 +
  47 + # Everything ok, so just increment the page count
  48 + hit_ = Hit.objects.get_or_create(content_type=content_type,
  49 + object_pk=self.pk)[0]
  50 + hit_.hits += 1
  51 + hit_.save()
... ...
src/hitcount/tests.py 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
... ...
src/hitcount/views.py 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +from django.shortcuts import render
  2 +
  3 +class HitCountViewMixin(object):
  4 + def get_object(self):
  5 + raise NotImplementedError
  6 +
  7 + def dispatch(self, request, *args, **kwargs):
  8 + response = super(HitCountViewMixin, self).dispatch(request,
  9 + *args, **kwargs)
  10 + if 200 <= response.status_code < 300:
  11 + obj = self.get_object()
  12 + if obj: obj.hit(request)
  13 + return response
... ...