-
-
Notifications
You must be signed in to change notification settings - Fork 485
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
312 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
*.pyc | ||
dist/ | ||
*.egg-info/ | ||
build/ | ||
MANIFEST | ||
.coverage | ||
.tox/ | ||
htmlcov/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
language: python | ||
|
||
python: | ||
- "2.6" | ||
- "2.7" | ||
|
||
env: | ||
- DJANGO=Django==1.2.7 SOUTH=1 | ||
- DJANGO=Django==1.3.7 SOUTH=1 | ||
- DJANGO=Django==1.4.5 SOUTH=1 | ||
- DJANGO=Django==1.5.1 SOUTH=1 | ||
- DJANGO=https://github.com/django/django/tarball/master SOUTH=1 | ||
- DJANGO=Django==1.3.7 SOUTH=0 | ||
|
||
install: | ||
- pip install coverage $DJANGO --use-mirrors | ||
- sh -c "if [ '$SOUTH' = '1' ]; then pip install South==0.7.6; fi" | ||
- sh -c "if [ '$COVERALLS' != '0' ]; then pip install coveralls; fi" | ||
|
||
script: coverage run -a --branch --include="simple_history/*" --omit="simple_history/tests/*" setup.py test | ||
|
||
matrix: | ||
include: | ||
- python: 2.5 | ||
env: DJANGO=Django==1.2.7 SOUTH=1 COVERALLS=0 | ||
- python: 2.5 | ||
env: DJANGO=Django==1.3.7 SOUTH=1 COVERALLS=0 | ||
- python: 2.5 | ||
env: DJANGO=Django==1.4.5 SOUTH=1 COVERALLS=0 | ||
|
||
after_success: coveralls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
================== | ||
django-simple-history | ||
================== | ||
|
||
.. image:: https://secure.travis-ci.org/treyhunner/django-simple-history.png?branch=master | ||
:target: http://travis-ci.org/treyhunner/django-simple-history | ||
.. image:: https://coveralls.io/repos/treyhunner/django-simple-history/badge.png?branch=master | ||
:target: https://coveralls.io/r/treyhunner/django-simple-history | ||
|
||
django-simple-history is a tool to store state of DB objects on every create/update/delete. It has been tested to work in django 1.X (including 1.2.3 as of 10/25/2010). | ||
|
||
Install | ||
------- | ||
Download the tar.gz, extract it and run the following inside the directory: | ||
|
||
.. code-block:: bash | ||
$ python setup.py install | ||
Basic usage | ||
----------- | ||
Using this package is _really_ simple; you just have to import HistoricalRecords and create an instance of it on every model you want to historically track. | ||
|
||
On your models you need to include the following line at the top: | ||
|
||
.. code-block:: python | ||
from simple_history.models import HistoricalRecords | ||
Then in your model class, include the following line: | ||
|
||
.. code-block:: python | ||
history = HistoricalRecords() | ||
Then from either the model class or from an instance, you can access history.all() which will give you either every history item of the class, or every history item of the specific instance. | ||
|
||
Example | ||
------- | ||
Models: | ||
|
||
.. code-block:: python | ||
class Poll(models.Model): | ||
question = models.CharField(max_length = 200) | ||
pub_date = models.DateTimeField('date published') | ||
history = HistoricalRecords() | ||
class Choice(models.Model): | ||
poll = models.ForeignKey(Poll) | ||
choice = models.CharField(max_length=200) | ||
votes = models.IntegerField() | ||
history = HistoricalRecords() | ||
Usage: | ||
|
||
.. code-block:: pycon | ||
>>> from poll.models import Poll, Choice | ||
>>> Poll.objects.all() | ||
[] | ||
>>> import datetime | ||
>>> p = Poll(question="what's up?", pub_date=datetime.datetime.now()) | ||
>>> p.save() | ||
>>> p | ||
<Poll: Poll object> | ||
>>> p.history.all() | ||
[<HistoricalPoll: Poll object as of 2010-10-25 18:03:29.855689>] | ||
>>> p.pub_date = datetime.datetime(2007,4,1,0,0) | ||
>>> p.save() | ||
>>> p.history.all() | ||
[<HistoricalPoll: Poll object as of 2010-10-25 18:04:13.814128>, <HistoricalPoll: Poll object as of 2010-10-25 18:03:29.855689>] | ||
>>> p.choice_set.create(choice='Not Much', votes=0) | ||
<Choice: Choice object> | ||
>>> p.choice_set.create(choice='The sky', votes=0) | ||
<Choice: Choice object> | ||
>>> c = p.choice_set.create(choice='Just hacking again', votes=0) | ||
>>> c.poll | ||
<Poll: Poll object> | ||
>>> c.history.all() | ||
[<HistoricalChoice: Choice object as of 2010-10-25 18:05:30.160595>] | ||
>>> Choice.history | ||
<simple_history.manager.HistoryManager object at 0x1cc4290> | ||
>>> Choice.history.all() | ||
[<HistoricalChoice: Choice object as of 2010-10-25 18:05:30.160595>, <HistoricalChoice: Choice object as of 2010-10-25 18:05:12.183340>, <HistoricalChoice: Choice object as of 2010-10-25 18:04:59.047351>] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env python | ||
import sys | ||
from os.path import abspath, dirname | ||
|
||
from django.conf import settings | ||
|
||
|
||
sys.path.insert(0, abspath(dirname(__file__))) | ||
|
||
|
||
if not settings.configured: | ||
settings.configure( | ||
INSTALLED_APPS=( | ||
'django.contrib.contenttypes', | ||
'django.contrib.auth', | ||
'simple_history', | ||
'simple_history.tests' | ||
), | ||
DATABASES={ | ||
'default': { | ||
'ENGINE': 'django.db.backends.sqlite3', | ||
} | ||
}, | ||
) | ||
|
||
|
||
def main(): | ||
from django.test.simple import DjangoTestSuiteRunner | ||
failures = DjangoTestSuiteRunner( | ||
verbosity=1, interactive=True, failfast=False).run_tests(['tests']) | ||
sys.exit(failures) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/sh | ||
coverage erase | ||
tox | ||
coverage html --include=simple_history/* --omit=simple_history/tests/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django.db import models | ||
from simple_history.models import HistoricalRecords | ||
|
||
|
||
class Poll(models.Model): | ||
question = models.CharField(max_length=200) | ||
pub_date = models.DateTimeField('date published') | ||
|
||
history = HistoricalRecords() | ||
|
||
|
||
class Choice(models.Model): | ||
poll = models.ForeignKey(Poll) | ||
choice = models.CharField(max_length=200) | ||
votes = models.IntegerField() | ||
|
||
history = HistoricalRecords() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from datetime import datetime, timedelta | ||
from django.test import TestCase | ||
|
||
from .models import Poll | ||
|
||
|
||
today = datetime(2021, 1, 1, 10, 0) | ||
tomorrow = today + timedelta(days=1) | ||
|
||
|
||
class HistoricalRecordsTest(TestCase): | ||
|
||
def assertDatetimesEqual(self, time1, time2): | ||
self.assertAlmostEqual(time1, time2, delta=timedelta(seconds=2)) | ||
|
||
def assertRecordValues(self, record, values_dict): | ||
for key, value in values_dict.items(): | ||
self.assertEqual(getattr(record, key), value) | ||
|
||
def test_create(self): | ||
p = Poll(question="what's up?", pub_date=today) | ||
p.save() | ||
history = p.history.all() | ||
record, = history | ||
self.assertRecordValues(record, { | ||
'question': "what's up?", | ||
'pub_date': today, | ||
'id': p.id, | ||
'history_type': "+" | ||
}) | ||
|
||
def test_update(self): | ||
Poll.objects.create(question="what's up?", pub_date=today) | ||
p = Poll.objects.get() | ||
p.pub_date = tomorrow | ||
p.save() | ||
history = p.history.all() | ||
update_record, create_record = history | ||
self.assertRecordValues(create_record, { | ||
'question': "what's up?", | ||
'pub_date': today, | ||
'id': p.id, | ||
'history_type': "+" | ||
}) | ||
self.assertRecordValues(update_record, { | ||
'question': "what's up?", | ||
'pub_date': tomorrow, | ||
'id': p.id, | ||
'history_type': "~" | ||
}) | ||
|
||
def test_delete(self): | ||
p = Poll.objects.create(question="what's up?", pub_date=today) | ||
poll_id = p.id | ||
p.delete() | ||
history = Poll.history.all() | ||
delete_record, create_record = history | ||
self.assertRecordValues(create_record, { | ||
'question': "what's up?", | ||
'pub_date': today, | ||
'id': poll_id, | ||
'history_type': "+" | ||
}) | ||
self.assertRecordValues(delete_record, { | ||
'question': "what's up?", | ||
'pub_date': today, | ||
'id': poll_id, | ||
'history_type': "-" | ||
}) |
Oops, something went wrong.