Skip to content

Commit dfad7d6

Browse files
committed
Added: getObject()
1 parent ca34099 commit dfad7d6

6 files changed

Lines changed: 53 additions & 35 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ v3.0
33
This is a major release so please test carefully.
44

55
* Removed: `old_state` of the object from database, but still the changes can be done against previous object.
6-
* Added: `get_history(reverse=True)` to get all object changes, this returns a Queryset so it can be filtered
7-
* Added: `View Data Changes` in Django Model Admin to see the object changes
8-
* Change: add urls under `tracker` namespace.
6+
* Added: `get_history(reverse=True)` to get all object changes, this returns a Queryset so it can be filtered.
7+
* Added: `get_object()` to the history Model to return the state of the object in that snapshot.
8+
* Added: `View Data Changes` in Django Model Admin to see the object changes.
9+
* Change: add urls under `tracker` namespace.
10+

ModelTracker/Tracker.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import lru_cache
2+
13
from django.db import models
24
import sys
35
from .models import *
@@ -8,14 +10,14 @@
810
import threading
911
import datetime
1012

13+
1114
class ModelTracker(models.Model):
1215
thread = threading.local()
1316

1417
def __init__(self,*args,**kwargs):
1518
models.Model.__init__(self, *args, **kwargs)
1619
#self.old_state = copy.deepcopy(self.__dict__)
1720

18-
1921
def get_history(self,reverse=True):
2022
"""Returns queryset"""
2123
q = History.objects.filter(table=self._meta.db_table, primary_key = self.pk)

ModelTracker/management/commands/restoreObject.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,23 @@
1-
from django.core.management.base import BaseCommand, CommandError
2-
import __future__
1+
from django.core.management.base import BaseCommand
32
from ModelTracker.models import History
4-
import datetime
5-
from django.apps import apps
6-
def getModel(table_name):
7-
return next((m for m in apps.get_models() if m._meta.db_table==table_name), None)
3+
84

95
class Command(BaseCommand):
106
help = 'Restore Object to old status'
117

128
def add_arguments(self, parser):
139
parser.add_argument('--id', nargs='?', type=str,default=None)
14-
parser.add_argument("--state",type=str,nargs='?',default="new")
10+
# parser.add_argument("--state",type=str,nargs='?',default="new")
1511
parser.add_argument("--user",type=str,nargs='?',default="CLI")
12+
13+
1614
def handle(self, *args, **options):
1715
if not options.get("id",None):
1816
print ("Change ID is needed")
1917
exit(1)
20-
print (options)
18+
2119
h = History.objects.get(id=int(options["id"]))
22-
model = getModel(h.table)
23-
if model == None:
24-
print("Can't find the Model")
25-
exit(2)
26-
d=[f.name for f in model._meta.get_fields()]
27-
if options["state"]=="old": state=h.old_state
28-
else: state=h.new_state
29-
keys2del=[]
30-
for key in state:
31-
if (key.startswith("_") and "_cache" in key) or (key not in d and not ("_id" in key and key[:-3] in d)):
32-
keys2del.append(key)
33-
if type(state[key])==type({}):
34-
if state[key].get("_type",None) == "datetime":
35-
state[key]=datetime.datetime.strptime(state[key]["value"],"%Y-%m-%d %H:%M:%S")
36-
elif state[key].get("_type",None) == "date":
37-
state[key]=datetime.datetime.strptime(state[key]["value"],"%Y-%m-%d")
38-
for key in keys2del:
39-
del state[key]
40-
41-
print(state)
42-
m=model(**state)
20+
m = h.get_object()
4321
m.save(options["user"],event_name="Restore Record to %s (%s)"%(options["id"],options["state"]))
4422

4523

ModelTracker/models.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
import datetime
2+
from functools import lru_cache
3+
14
from django.db import models
5+
from django.apps import apps
6+
7+
from ModelTracker.utils import get_fields,get_model
8+
9+
210
try:
311
from django.db.models import JSONField
412
except ImportError:
@@ -8,7 +16,6 @@
816
raise ImportError("Can't find a JSONField implementation, please install jsonfield if django < 4.0")
917

1018

11-
1219
class History(models.Model):
1320
id=models.AutoField(primary_key=True)
1421
name=models.CharField(max_length=255,default="")
@@ -19,8 +26,26 @@ class History(models.Model):
1926
done_by=models.CharField(max_length=255)
2027
done_on=models.DateTimeField(auto_now_add=True)
2128

29+
def get_object(self):
30+
model = get_model(self.table)
31+
fields = get_fields(model)
32+
keys2del = []
33+
state = self.new_state
34+
for key in state:
35+
if (key.startswith("_") and "_cache" in key) or (key not in fields and not ("_id" in key and key[:-3] in fields)):
36+
keys2del.append(key)
37+
if type(state[key])==type({}):
38+
if state[key].get("_type",None) == "datetime":
39+
state[key]=datetime.datetime.strptime(state[key]["value"],"%Y-%m-%d %H:%M:%S")
40+
elif state[key].get("_type",None) == "date":
41+
state[key]=datetime.datetime.strptime(state[key]["value"],"%Y-%m-%d")
42+
for key in keys2del:
43+
del state[key]
44+
return model(**state)
45+
2246
def __eq__(self, other):
2347
return self.id == other.id
48+
2449
def __str__(self):
2550
if self.name:
2651
return "%s for %s in %s"%(self.name, self.primary_key, self.table)

ModelTracker/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from functools import lru_cache
2+
3+
from django.apps import apps
4+
5+
6+
@lru_cache(50)
7+
def get_model(table_name):
8+
return next((m for m in apps.get_models() if m._meta.db_table==table_name), None)
9+
10+
def get_fields(model):
11+
return [f.name for f in model._meta.get_fields()]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name='django-model-tracker',
20-
version='3.0b1',
20+
version='3.0b2',
2121
description='Track Django Model Objects over time',
2222
author='Mohamed El-Kalioby',
2323
author_email = 'mkalioby@mkalioby.com',

0 commit comments

Comments
 (0)