Add support for deferred fields in the FieldTracker

This commit is contained in:
Michael van Tellingen 2014-03-01 13:34:17 +01:00
parent 1bab9c492d
commit 6ffae1ad8f
3 changed files with 48 additions and 2 deletions

View file

@ -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 file

@ -1436,7 +1436,19 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
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 file

@ -4,6 +4,7 @@ from copy import deepcopy
from django.db import models
from django.core.exceptions import FieldError
from django.db.models.query_utils import DeferredAttribute
class FieldInstanceTracker(object):
@ -11,6 +12,7 @@ class FieldInstanceTracker(object):
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 @@ class FieldInstanceTracker(object):
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 @@ class FieldInstanceTracker(object):
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):