Skip to content

Commit d112ffc

Browse files
committed
Fixed VersionsForeignKey fields to update all related objects.
1 parent f5c4ce4 commit d112ffc

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

docs/todo.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
Things TODO
22
###########
33

4-
#. Versioned ManyToManyFields on a versioned object (the ManyToManyField should not have to be a VersionsModel object)
5-
#. Reverse ForeignKey relationships should maintain, even if the related object is currently pointing to a new objectm but pointing to our versioned object in the past.
4+
#. VersionsForeignKey relationships only get updated if the actual attribute gets set, however, if they user sets the attribute_id directly, we do not get alerted of the changes.

versions/fields.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
from versions.repo import Versions
55

66
def stage_related_models(sender, instance, created, **kwargs):
7-
for field in instance._meta.local_fields:
8-
if isinstance(field, VersionsForeignKey):
9-
model = getattr(instance, field.name)
7+
"""
8+
This signal handler is used to alert objects to changes in the ForeignKey of related objects.
9+
We capture both the creation of a new ForeignKey relationship, as well as the removal or changing
10+
of an existing ForeignKey relationship.
11+
"""
12+
for field, models in instance._versions_related_updates.items():
13+
for model in models:
1014
vc = Versions()
1115
vc.stage(model)
1216

@@ -15,10 +19,23 @@ class VersionsForeignKey(related.ForeignKey):
1519
A field used to allow VersionsModel objects to track non-versioned ForeignKey objects associated with
1620
a model at a given revision.
1721
"""
22+
def contribute_to_class(self, cls, name):
23+
cls._versions_related_updates = {}
24+
super(VersionsForeignKey, self).contribute_to_class(cls, name)
25+
setattr(cls, self.name, VersionsReverseSingleRelatedObjectDescriptor(self))
26+
1827
def contribute_to_related_class(self, cls, related):
1928
super(VersionsForeignKey, self).contribute_to_related_class(cls, related)
2029
setattr(cls, related.get_accessor_name(), VersionsForeignRelatedObjectsDescriptor(related))
21-
signals.post_save.connect(stage_related_models, sender=related.model)
30+
signals.post_save.connect(stage_related_models, sender=related.model, dispatch_uid='versions_foreignkey_related_object_update')
31+
32+
class VersionsReverseSingleRelatedObjectDescriptor(related.ReverseSingleRelatedObjectDescriptor):
33+
def __set__(self, instance, value):
34+
old_value = getattr(instance, self.field.name, None)
35+
result = super(VersionsReverseSingleRelatedObjectDescriptor, self).__set__(instance, value)
36+
if old_value != value:
37+
instance._versions_related_updates[self.field.name] = [ x for x in [old_value, value] if x is not None ]
38+
return result
2239

2340
class VersionsForeignRelatedObjectsDescriptor(related.ForeignRelatedObjectsDescriptor):
2441
def __get__(self, instance, instance_type=None):

0 commit comments

Comments
 (0)