Skip to content

Commit

Permalink
Catch deferred attribute exception
Browse files Browse the repository at this point in the history
  • Loading branch information
slurms committed Mar 29, 2019
1 parent c4a252d commit 959786e
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CHANGES

master (unreleased)
-------------------
- Catch `AttributeError` for deferred abstract fields, fixes GH-331.
- Update documentation to explain usage of `timeframed` model manager, fixes GH-118
- Honor `OneToOneField.parent_link=False`.
- Fix handling of deferred attributes on Django 1.10+, fixes GH-278
Expand All @@ -14,7 +15,7 @@ master (unreleased)
- Support `reversed` for all kinds of `Choices` objects, fixes GH-309
- Fix Model instance non picklable GH-330
- Fix patched `save` in FieldTracker
- Upgrades test requirements (pytest, pytest-django, pytest-cov) and
- Upgrades test requirements (pytest, pytest-django, pytest-cov) and
skips tox test with Python 3.5 and Django (trunk)

3.1.2 (2018.05.09)
Expand Down
5 changes: 4 additions & 1 deletion model_utils/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ def __get__(self, instance, owner):
if instance is None:
return self
was_deferred = self.field_name in instance.get_deferred_fields()
value = self.descriptor.__get__(instance, owner)
try:
value = self.descriptor.__get__(instance, owner)
except AttributeError:
value = self.descriptor
if was_deferred:
tracker_instance = getattr(instance, self.tracker_attname)
tracker_instance.saved_data[self.field_name] = deepcopy(value)
Expand Down
15 changes: 15 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ def get_queryset(self):
return ByAuthorQuerySet(self.model, **kwargs).filter(feature=True)


class AbstractTracked(models.Model):
number = 1

class Meta:
abstract = True


class Tracked(models.Model):
name = models.CharField(max_length=20)
number = models.IntegerField()
Expand All @@ -240,6 +247,14 @@ class TrackedFK(models.Model):
custom_tracker_without_id = FieldTracker(fields=['fk'])


class TrackedAbstract(AbstractTracked):
name = models.CharField(max_length=20)
number = models.IntegerField()
mutable = MutableField(default=None)

tracker = FieldTracker()


class TrackedNotDefault(models.Model):
name = models.CharField(max_length=20)
number = models.IntegerField()
Expand Down
7 changes: 6 additions & 1 deletion tests/test_fields/test_field_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from model_utils.tracker import DescriptorWrapper
from tests.models import (
Tracked, TrackedFK, InheritedTrackedFK, TrackedNotDefault, TrackedNonFieldAttr, TrackedMultiple,
InheritedTracked, TrackedFileField,
InheritedTracked, TrackedFileField, TrackedAbstract,
ModelTracked, ModelTrackedFK, ModelTrackedNotDefault, ModelTrackedMultiple, InheritedModelTracked,
)

Expand Down Expand Up @@ -785,3 +785,8 @@ def test_child_fields_not_tracked(self):
self.name2 = 'test'
self.assertEqual(self.tracker.previous('name2'), None)
self.assertTrue(self.tracker.has_changed('name2'))


class AbstractModelTrackerTests(FieldTrackerTestCase):

tracked_class = TrackedAbstract

0 comments on commit 959786e

Please sign in to comment.