Permalink
Browse files

Add support for deferred fields in the FieldTracker

  • Loading branch information...
1 parent 1bab9c4 commit 6ffae1ad8ffcfa6f9c3354e34f9ee5415e656f62 Michael van Tellingen committed Mar 1, 2014
Showing with 48 additions and 2 deletions.
  1. +1 −0 AUTHORS.rst
  2. +13 −1 model_utils/tests/tests.py
  3. +34 −1 model_utils/tracker.py
View
@@ -16,6 +16,7 @@ Jannis Leidel <jannis@leidel.info>
Javier García Sogo <jgsogo@gmail.com>
Jeff Elmore <jeffelmore.org>
Keryn Knight <kerynknight.com>
+Michael van Tellingen <michaelvantellingen@gmail.com>
Mikhail Silonov <silonov.pro>
Patryk Zawadzki <patrys@room-303.com>
Paul McLanahan <paul@mclanahan.net>
View
@@ -1436,7 +1436,19 @@ def test_with_deferred(self):
self.instance.name = 'new age'
self.instance.number = 1
self.instance.save()
- items = list(self.tracked_class.objects.only('name').all())
+ item = list(self.tracked_class.objects.only('name').all())[0]
+ self.assertTrue(item.tracker.deferred_fields)
+
+ self.assertEqual(item.tracker.previous('number'), None)
+ self.assertTrue('number' in item.tracker.deferred_fields)
+
+ self.assertEqual(item.number, 1)
+ self.assertTrue('number' not in item.tracker.deferred_fields)
+ self.assertEqual(item.tracker.previous('number'), 1)
+ self.assertFalse(item.tracker.has_changed('number'))
+
+ item.number = 2
+ self.assertTrue(item.tracker.has_changed('number'))
class FieldTrackedModelCustomTests(FieldTrackerTestCase,
View
@@ -4,13 +4,15 @@
from django.db import models
from django.core.exceptions import FieldError
+from django.db.models.query_utils import DeferredAttribute
class FieldInstanceTracker(object):
def __init__(self, instance, fields, field_map):
self.instance = instance
self.fields = fields
self.field_map = field_map
+ self.init_deferred_fields()
def get_field_value(self, field):
return getattr(self.instance, self.field_map[field])
@@ -30,7 +32,14 @@ def set_saved_fields(self, fields=None):
def current(self, fields=None):
"""Returns dict of current values for all tracked fields"""
if fields is None:
- fields = self.fields
+ if self.deferred_fields:
+ fields = [
+ field for field in self.fields
+ if field not in self.deferred_fields
+ ]
+ else:
+ fields = self.fields
+
return dict((f, self.get_field_value(f)) for f in fields)
def has_changed(self, field):
@@ -52,6 +61,30 @@ def changed(self):
if self.has_changed(field)
)
+ def init_deferred_fields(self):
+ self.deferred_fields = []
+ if not self.instance._deferred:
+ return
+
+ class DeferredAttributeTracker(DeferredAttribute):
+ def __get__(field, instance, owner):
+ data = instance.__dict__
+ if data.get(field.field_name, field) is field:
+ self.deferred_fields.remove(field.field_name)
+ value = super(DeferredAttributeTracker, field).__get__(
+ instance, owner)
+ self.saved_data[field.field_name] = deepcopy(value)
+ return data[field.field_name]
+
+ for field in self.fields:
+ field_obj = self.instance.__class__.__dict__.get(field)
+ if isinstance(field_obj, DeferredAttribute):
+ self.deferred_fields.append(field)
+
+ field_tracker = DeferredAttributeTracker(
+ field_obj.field_name, None)
+ setattr(self.instance.__class__, field, field_tracker)
+
class FieldTracker(object):

0 comments on commit 6ffae1a

Please sign in to comment.