mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Merge pull request #115 from mvantellingen/feature/deferred-suport
Add support for deferred fields in the FieldTracker
This commit is contained in:
commit
e525f395d3
3 changed files with 58 additions and 1 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1432,6 +1432,24 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
|
|||
self.assertEqual(in_db.number, self.instance.number)
|
||||
self.assertEqual(in_db.mutable, self.instance.mutable)
|
||||
|
||||
def test_with_deferred(self):
|
||||
self.instance.name = 'new age'
|
||||
self.instance.number = 1
|
||||
self.instance.save()
|
||||
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,
|
||||
FieldTrackerCommonTests):
|
||||
|
|
|
|||
|
|
@ -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,35 @@ 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)
|
||||
|
||||
# Django 1.4
|
||||
model = None
|
||||
if hasattr(field_obj, 'model_ref'):
|
||||
model = field_obj.model_ref()
|
||||
|
||||
field_tracker = DeferredAttributeTracker(
|
||||
field_obj.field_name, model)
|
||||
setattr(self.instance.__class__, field, field_tracker)
|
||||
|
||||
|
||||
class FieldTracker(object):
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue