Skip to content

Commit 3ad86e1

Browse files
committed
Initial commit
0 parents  commit 3ad86e1

11 files changed

+663
-0
lines changed

.gitignore

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
*.pyc
2+
*~
3+
.idea
4+
.project
5+
.pydevproject
6+
*.geany
7+
docs/_build
8+
build
9+
dist
10+
*.egg*
11+
example/local_settings.py
12+
13+
# Unit test / coverage reports
14+
htmlcov/
15+
.tox/
16+
.coverage
17+
.coverage.*
18+
coverage.xml
19+
20+
.ropeproject/*
21+
pep8.txt
22+
*.bak
23+
.#*
24+
\#*
25+
*.db
26+
*.tmp
27+
virtualenv
28+
.DS_Store
29+
30+
*.prefs

README.rst

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
=============================
2+
Welcome to django-trackstats!
3+
=============================
4+
5+
.. image:: https://badge.fury.io/py/django-trackstats.png
6+
:target: http://badge.fury.io/py/django-trackstats
7+
8+
.. image:: https://travis-ci.org/pennersr/django-trackstats.png
9+
:target: http://travis-ci.org/pennersr/django-trackstats
10+
11+
.. image:: https://img.shields.io/pypi/v/django-trackstats.svg
12+
:target: https://pypi.python.org/pypi/django-trackstats
13+
14+
.. image:: https://coveralls.io/repos/pennersr/django-trackstats/badge.png?branch=master
15+
:alt: Coverage Status
16+
:target: https://coveralls.io/r/pennersr/django-trackstats
17+
18+
.. image:: https://pennersr.github.io/img/bitcoin-badge.svg
19+
:target: https://blockchain.info/address/1AJXuBMPHkaDCNX2rwAy34bGgs7hmrePEr
20+
21+
Keep track of your statistics.
22+
23+
Source code
24+
http://github.com/pennersr/django-allauth
25+
26+
27+
Concepts
28+
========
29+
30+
The following concepts are used:
31+
32+
Metric
33+
A piece of information to keep track of. For example, "Order count",
34+
or "Number of users signed up".
35+
36+
Domain
37+
Metrics are organized in groups, each group is called a domain. For
38+
example you can have a "shopping" domain with metrics such as "Order
39+
count", "Items sold", "Products viewed", and a "users" domain with
40+
"Login count", "Signup count". Or, in case you are tracking external
41+
statistics from social networks, you may introduce a "Twitter"
42+
domain, and metrics "Followers count".
43+
44+
Subject
45+
When storing statistics we are storing values relating to a specific
46+
subject. For example, when keeping track of the "comment count" per
47+
user, the subject is clearly the user. Yet, if you are keeping track
48+
of the "Order count" globally for the whole webshop, the subject is
49+
less clear. You could decide to choose to use the `Site` instance
50+
where your webshop is running at. If not specified, the domain of the
51+
metric is used as the subject.
52+
53+
Statistic
54+
Used to store the actual values by date, for a specific metric, relating to
55+
a specific subject.
56+
57+
Period
58+
The time period for which the stored value holds. For example, you
59+
can keep track of cumulative, all-time, numbers (`Period.LIFETIME`),
60+
store incremental values on a daily basis (`Period.DAY`), or keep
61+
track of a rolling count for the last 7 days (`Period.WEEK`).
62+
63+
64+
Usage
65+
=====
66+
67+
First, setup your domains::
68+
69+
from trackstats.models import Domain
70+
71+
Domain.objects.SHOPPING = Domain.objects.register(
72+
ref='shopping',
73+
name='Shopping')
74+
Domain.objects.USERS = Domain.object.register(
75+
ref='users',
76+
name='Users')
77+
Domain.objects.TWITTER = Domain.object.register(
78+
ref='twitter',
79+
name='Twitter')
80+
81+
Define a few metrics::
82+
83+
from trackstats.models import Domain, Metric
84+
85+
Metric.objects.SHOPPING_ORDER_COUNT = Metric.objects.register(
86+
domain=Domain.objects.SHOPPING,
87+
ref='order_count',
88+
name='Number of orders sold')
89+
Metric.objects.USERS_USER_COUNT = Metric.objects.register(
90+
domain=Domain.objects.USERS,
91+
ref='user_count',
92+
name='Number of users signed up')
93+
Metric.objects.TWITTER_FOLLOWER = Metric.objects.register(
94+
# Matches Twitter API
95+
ref='followers_count',
96+
domain=Domain.objects.TWITTER)
97+
98+
Now, let's store some statistics::
99+
100+
from trackstats.models import Statistic, Domain, Metric, Period
101+
102+
# All-time, cumulative, statistic
103+
n = Order.objects.all().count()
104+
Statistic.objects.record(
105+
metric=Metric.objects.SHOPPING_ORDER_COUNT,
106+
subject=Site.objects.get_current(),
107+
value=n,
108+
Period=Period.LIFETIME)
109+
110+
# Users signed up, at a specific date
111+
dt = date.today()
112+
n = User.objects.filter(
113+
date_joined__day=dt.day,
114+
date_joined__month=dt.month,
115+
date_joined__year=dt.year).count()
116+
Statistic.objects.record(
117+
metric=Metric.objects.USERS_USER_COUNT,
118+
value=n,
119+
Period=Period.DAY)

setup.py

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python
2+
from __future__ import unicode_literals
3+
import codecs
4+
import os
5+
from setuptools import setup, find_packages
6+
from setuptools.command.test import test as TestCommand
7+
8+
import trackstats
9+
10+
11+
class DjangoTests(TestCommand):
12+
13+
def finalize_options(self):
14+
TestCommand.finalize_options(self)
15+
self.test_args = []
16+
self.test_suite = True
17+
18+
def run_tests(self):
19+
from django.core import management
20+
DSM = 'DJANGO_SETTINGS_MODULE'
21+
if DSM not in os.environ:
22+
os.environ[DSM] = 'trackstats.tests.settings'
23+
management.execute_from_command_line()
24+
25+
26+
def read_files(*filenames):
27+
"""
28+
Output the contents of one or more files to a single concatenated string.
29+
"""
30+
output = []
31+
for filename in filenames:
32+
f = codecs.open(filename, encoding='utf-8')
33+
try:
34+
output.append(f.read())
35+
finally:
36+
f.close()
37+
return '\n\n'.join(output)
38+
39+
# Dynamically calculate the version based on trackstats.VERSION.
40+
version = trackstats.__version__
41+
42+
setup(
43+
name='django-trackstats',
44+
version=version,
45+
url='http://github.com/pennersr/django-trackstats',
46+
description='Statistics storage for Django',
47+
long_description=read_files('README.rst'),
48+
author='Raymond Penners',
49+
author_email='[email protected]',
50+
platforms=['any'],
51+
packages=find_packages(),
52+
include_package_data=True,
53+
install_requires=[
54+
'django>=1.9',
55+
],
56+
cmdclass={'test': DjangoTests},
57+
classifiers=[
58+
'Development Status :: 4 - Beta',
59+
'Environment :: Web Environment',
60+
'Framework :: Django',
61+
'Intended Audience :: Developers',
62+
'License :: OSI Approved :: BSD License',
63+
'Operating System :: OS Independent',
64+
'Programming Language :: Python',
65+
'Programming Language :: Python :: 2.6',
66+
'Programming Language :: Python :: 2.7',
67+
'Programming Language :: Python :: 3.3',
68+
'Programming Language :: Python :: 3.4',
69+
'Topic :: Software Development :: Libraries :: Application Frameworks',
70+
'Topic :: Software Development :: Libraries :: Python Modules',
71+
],
72+
zip_safe=False,
73+
)

trackstats/__init__.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
______ __ _____ __ __
3+
/_ __/________ ______/ /__/ ___// /_____ _/ /______
4+
/ / / ___/ __ `/ ___/ //_/\__ \/ __/ __ `/ __/ ___/
5+
/ / / / / /_/ / /__/ ,< ___/ / /_/ /_/ / /_(__ )
6+
/_/ /_/ \__,_/\___/_/|_|/____/\__/\__,_/\__/____/
7+
8+
"""
9+
VERSION = (0, 1, 0, 'dev', 0)
10+
11+
__title__ = 'django-trackstats'
12+
__version_info__ = VERSION
13+
__version__ = '.'.join(map(str, VERSION[:3])) + ('-{}{}'.format(
14+
VERSION[3], VERSION[4] or '') if VERSION[3] != 'final' else '')
15+
__author__ = 'Raymond Penners'
16+
__license__ = 'MIT'
17+
__copyright__ = 'Copyright 2016 Raymond Penners and contributors'

trackstats/admin.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from django.contrib import admin
2+
3+
from .models import Domain, Metric, Statistic
4+
5+
6+
@admin.register(Domain)
7+
class DomainAdmin(admin.ModelAdmin):
8+
list_display = (
9+
'ref',
10+
'name')
11+
12+
13+
@admin.register(Metric)
14+
class MetricAdmin(admin.ModelAdmin):
15+
search_fields = (
16+
'ref',
17+
'name')
18+
list_display = (
19+
'ref',
20+
'name')
21+
list_filter = (
22+
'domain',)
23+
24+
25+
@admin.register(Statistic)
26+
class StatisticAdmin(admin.ModelAdmin):
27+
list_display = (
28+
'date',
29+
'metric',
30+
'subject_type',
31+
'subject',
32+
'value'
33+
)
34+
date_hierarchy = 'date'
35+
list_filter = (
36+
'date',
37+
'metric__domain',
38+
'metric')

trackstats/migrations/0001_initial.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.9.1 on 2016-01-28 22:34
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
import django.db.models.deletion
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
initial = True
12+
13+
dependencies = [
14+
('contenttypes', '0002_remove_content_type_name'),
15+
]
16+
17+
operations = [
18+
migrations.CreateModel(
19+
name='Domain',
20+
fields=[
21+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22+
('ref', models.CharField(help_text=b'Unique reference ID for this domain', max_length=100, unique=True)),
23+
('name', models.CharField(blank=True, help_text=b'Short descriptive name', max_length=100)),
24+
],
25+
),
26+
migrations.CreateModel(
27+
name='Metric',
28+
fields=[
29+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
30+
('ref', models.CharField(help_text=b'Unique reference ID for this metric within the domain', max_length=100)),
31+
('name', models.CharField(blank=True, help_text=b'Short descriptive name', max_length=100)),
32+
('description', models.TextField(blank=True, help_text=b'Description')),
33+
('domain', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='trackstats.Domain')),
34+
],
35+
),
36+
migrations.CreateModel(
37+
name='Statistic',
38+
fields=[
39+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
40+
('subject_id', models.PositiveIntegerField()),
41+
('value', models.BigIntegerField(null=True)),
42+
('period', models.IntegerField(choices=[(86400, b'Day'), (604800, b'Week'), (2419200, b'28 days'), (2592000, b'Month'), (0, b'Lifetime')])),
43+
('date', models.DateField(db_index=True)),
44+
('metric', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='trackstats.Metric')),
45+
('subject_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='contenttypes.ContentType')),
46+
],
47+
),
48+
migrations.AlterUniqueTogether(
49+
name='statistic',
50+
unique_together=set([('date', 'metric', 'subject_type', 'subject_id', 'period')]),
51+
),
52+
migrations.AlterUniqueTogether(
53+
name='metric',
54+
unique_together=set([('domain', 'ref')]),
55+
),
56+
]

trackstats/migrations/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)