From e795c6a2033e37ad30450303a883e20d1603798e Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Fri, 15 Jul 2016 02:50:21 +0000 Subject: [PATCH 01/21] Make model changes work with mongo engine. --- django_model_changes/changes.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 3d0d595..a7e6048 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -1,4 +1,4 @@ -from django.db.models import signals +from mongoengine import signals from .signals import post_change @@ -62,18 +62,18 @@ class ChangesMixin(object): """ def __init__(self, *args, **kwargs): - super(ChangesMixin, self).__init__(*args, **kwargs) - self._states = [] self._save_state(new_instance=True) + + super(ChangesMixin, self).__init__(*args, **kwargs) signals.post_save.connect( _post_save, sender=self.__class__, - dispatch_uid='django-changes-%s' % self.__class__.__name__ + # dispatch_uid='django-changes-%s' % self.__class__.__name__ ) signals.post_delete.connect( _post_delete, sender=self.__class__, - dispatch_uid='django-changes-%s' % self.__class__.__name__ + # dispatch_uid='django-changes-%s' % self.__class__.__name__ ) def _save_state(self, new_instance=False, event_type='save'): @@ -99,10 +99,7 @@ def current_state(self): """ Returns a ``field -> value`` dict of the current state of the instance. """ - field_names = set() - [field_names.add(f.name) for f in self._meta.local_fields] - [field_names.add(f.attname) for f in self._meta.local_fields] - return dict([(field_name, getattr(self, field_name)) for field_name in field_names]) + return self.attributes() def previous_state(self): """ @@ -123,7 +120,12 @@ def old_state(self): return self._states[0] def _changes(self, other, current): - return dict([(key, (was, current[key])) for key, was in other.iteritems() if was != current[key]]) + res = {} + for key in set(other.keys()) | set(current.keys()): + was, now = other.get(key), current.get(key) + if was != now: + res[key] = (was, now) + return res def changes(self): """ @@ -198,9 +200,9 @@ def previous_instance(self): return self.__class__(**self.previous_state()) -def _post_save(sender, instance, **kwargs): - instance._save_state(new_instance=False, event_type=SAVE) +def _post_save(sender, **kwargs): + kwargs['document']._save_state(new_instance=False, event_type=SAVE) -def _post_delete(sender, instance, **kwargs): - instance._save_state(new_instance=False, event_type=DELETE) +def _post_delete(sender, **kwargs): + kwargs['document']._save_state(new_instance=False, event_type=DELETE) From 004d7f5672d787ebf69060a120354076cc4eb9fa Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Tue, 26 Jul 2016 15:14:24 +0000 Subject: [PATCH 02/21] Ignore the compiled egg. --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..11041c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.egg-info From c220c0c920f89e6e16ba06ff8a6c8ac342acc44e Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Tue, 2 Aug 2016 08:15:29 +0000 Subject: [PATCH 03/21] Use data instead of attributes. --- django_model_changes/changes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index a7e6048..29da373 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -63,6 +63,10 @@ class ChangesMixin(object): def __init__(self, *args, **kwargs): self._states = [] + + if not hasattr(self, '_data'): + self._data = {} + self._save_state(new_instance=True) super(ChangesMixin, self).__init__(*args, **kwargs) @@ -99,7 +103,7 @@ def current_state(self): """ Returns a ``field -> value`` dict of the current state of the instance. """ - return self.attributes() + return dict(self._data) def previous_state(self): """ From 10ee189c973d85da154dcd5b6465cbad5195e34a Mon Sep 17 00:00:00 2001 From: Aswinkumar Rajendiran Date: Wed, 28 Sep 2016 12:35:52 -0700 Subject: [PATCH 04/21] Ignore pyc files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 11041c7..4e5c320 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.egg-info +*.pyc + From 5fd87001553ef2b0e4958d23b37eb88c38c17b7c Mon Sep 17 00:00:00 2001 From: Aswinkumar Rajendiran Date: Fri, 7 Oct 2016 18:46:17 -0700 Subject: [PATCH 05/21] Save modal state before or after initializing the fields based on the presence of id. --- django_model_changes/changes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 29da373..61ba4e3 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -66,11 +66,15 @@ def __init__(self, *args, **kwargs): if not hasattr(self, '_data'): self._data = {} - - self._save_state(new_instance=True) - + + if not 'id' in kwargs: + self._save_state(new_instance=True) + super(ChangesMixin, self).__init__(*args, **kwargs) + if self.id: + self._save_state() + signals.post_save.connect( _post_save, sender=self.__class__, # dispatch_uid='django-changes-%s' % self.__class__.__name__ From db641b89ebbecbcf449fc49be1c7ab4155aa4595 Mon Sep 17 00:00:00 2001 From: Rohit Hiwale Date: Sat, 19 Nov 2016 19:19:30 -0800 Subject: [PATCH 06/21] deep copy for on_cache current_state snapshotting --- django_model_changes/changes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 61ba4e3..1aa9d37 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -1,3 +1,5 @@ +import copy + from mongoengine import signals from .signals import post_change @@ -107,7 +109,7 @@ def current_state(self): """ Returns a ``field -> value`` dict of the current state of the instance. """ - return dict(self._data) + return copy.deepcopy(dict(self._data)) def previous_state(self): """ From 5d5ad617770c3d93d02cd846c31dea8bea02304b Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 24 Nov 2016 20:00:27 +0000 Subject: [PATCH 07/21] Speedup changes. 20x. --- django_model_changes/changes.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 1aa9d37..43cf43d 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -1,7 +1,5 @@ import copy - from mongoengine import signals - from .signals import post_change SAVE = 0 @@ -75,7 +73,7 @@ def __init__(self, *args, **kwargs): super(ChangesMixin, self).__init__(*args, **kwargs) if self.id: - self._save_state() + self._save_state(new_instance=True) signals.post_save.connect( _post_save, sender=self.__class__, @@ -109,7 +107,15 @@ def current_state(self): """ Returns a ``field -> value`` dict of the current state of the instance. """ - return copy.deepcopy(dict(self._data)) + def _try_copy(v): + if isinstance(v, (list, dict)): return copy.copy(v) # Shallow copy + return v + + # First level shallow copy. + return {k: _try_copy(v) for k, v in self._data.iteritems()} + + # The fastest but in-accurate version. + # return dict(self._data) def previous_state(self): """ From f4e1370aca65e137b2be6748487f69a137d342c7 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Sat, 4 Feb 2017 11:59:43 +0000 Subject: [PATCH 08/21] Work well with reload. --- django_model_changes/changes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 43cf43d..2eb757b 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -214,6 +214,12 @@ def previous_instance(self): Returns an instance of this model in its previous state. """ return self.__class__(**self.previous_state()) + + def reload(self, *args, **kwargs): + res = super(ChangesMixin, self).reload(*args, **kwargs) + self._states = [] + self._save_state(new_instance=True) + return res def _post_save(sender, **kwargs): From 7c90f00453b87b1b48aaf14ee6cf15c6c90ff357 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Sat, 4 Feb 2017 11:59:43 +0000 Subject: [PATCH 09/21] Work well with reload. --- django_model_changes/changes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 43cf43d..2eb757b 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -214,6 +214,12 @@ def previous_instance(self): Returns an instance of this model in its previous state. """ return self.__class__(**self.previous_state()) + + def reload(self, *args, **kwargs): + res = super(ChangesMixin, self).reload(*args, **kwargs) + self._states = [] + self._save_state(new_instance=True) + return res def _post_save(sender, **kwargs): From 4db08ff852cfd3b230fa21b98aeb0d27392252e3 Mon Sep 17 00:00:00 2001 From: Mohit Mittal Date: Wed, 22 Feb 2017 11:22:16 -0800 Subject: [PATCH 10/21] Send changes to post_change hooks --- django_model_changes/changes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 2eb757b..6d7ac56 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -101,7 +101,7 @@ def _save_state(self, new_instance=False, event_type='save'): # Send post_change signal unless this is a new instance if not new_instance: - post_change.send(sender=self.__class__, instance=self) + post_change.send(sender=self.__class__, instance=self, changes=self.old_changes()) def current_state(self): """ From a0cf93d50912fdb006d2dbf1b2b91a39a57ea5ff Mon Sep 17 00:00:00 2001 From: sauravshah Date: Mon, 20 Mar 2017 12:03:54 +0530 Subject: [PATCH 11/21] Add kwargs --- django_model_changes/changes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 6d7ac56..1edb093 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -84,7 +84,7 @@ def __init__(self, *args, **kwargs): # dispatch_uid='django-changes-%s' % self.__class__.__name__ ) - def _save_state(self, new_instance=False, event_type='save'): + def _save_state(self, new_instance=False, event_type='save', **kwargs): # Pipe the pk on deletes so that a correct snapshot of the current # state can be taken. if event_type == DELETE: @@ -101,7 +101,7 @@ def _save_state(self, new_instance=False, event_type='save'): # Send post_change signal unless this is a new instance if not new_instance: - post_change.send(sender=self.__class__, instance=self, changes=self.old_changes()) + post_change.send(sender=self.__class__, instance=self, changes=self.old_changes(), **kwargs) def current_state(self): """ @@ -223,8 +223,8 @@ def reload(self, *args, **kwargs): def _post_save(sender, **kwargs): - kwargs['document']._save_state(new_instance=False, event_type=SAVE) + kwargs['document']._save_state(new_instance=False, event_type=SAVE, **kwargs) def _post_delete(sender, **kwargs): - kwargs['document']._save_state(new_instance=False, event_type=DELETE) + kwargs['document']._save_state(new_instance=False, event_type=DELETE, **kwargs) From 3c62fdaac1e7fb4634a309df708139aa73f259e3 Mon Sep 17 00:00:00 2001 From: sauravshah Date: Sun, 2 Jul 2017 17:10:21 +0530 Subject: [PATCH 12/21] Add type check for DocumentProxy --- django_model_changes/changes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 1edb093..a0a1ba9 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -1,5 +1,7 @@ import copy from mongoengine import signals +from mongoengine.base.proxy import DocumentProxy + from .signals import post_change SAVE = 0 @@ -108,6 +110,8 @@ def current_state(self): Returns a ``field -> value`` dict of the current state of the instance. """ def _try_copy(v): + if type(v) is DocumentProxy: + return v if isinstance(v, (list, dict)): return copy.copy(v) # Shallow copy return v From 51c852ea7d657f7b92834e20ea58c3cfd7492a29 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Wed, 4 Oct 2017 23:29:29 +0000 Subject: [PATCH 13/21] skip saving states in Historical models. --- django_model_changes/changes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index a0a1ba9..41b50bc 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -87,6 +87,9 @@ def __init__(self, *args, **kwargs): ) def _save_state(self, new_instance=False, event_type='save', **kwargs): + if "Historical" in self.__class__.__name__: + return + # Pipe the pk on deletes so that a correct snapshot of the current # state can be taken. if event_type == DELETE: From 72a4e6b2ff2054827e3f1bfb8e3e54a69451699c Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 00:08:58 +0000 Subject: [PATCH 14/21] kill django model changes. --- django_model_changes/changes.py | 65 --------------------------------- 1 file changed, 65 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 41b50bc..8bd2316 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -9,74 +9,9 @@ class ChangesMixin(object): - """ - ChangesMixin keeps track of changes for model instances. - - It allows you to retrieve the following states from an instance: - - 1. current_state() - The current state of the instance. - 2. previous_state() - The state of the instance **after** it was created, saved - or deleted the last time. - 3. old_state() - The previous previous_state(), i.e. the state of the - instance **before** it was created, saved or deleted the - last time. - - It also provides convenience methods to get changes between states: - - 1. changes() - Changes from previous_state to current_state. - 2. previous_changes() - Changes from old_state to previous_state. - 3. old_changes() - Changes from old_state to current_state. - - And the following methods to determine if an instance was/is persisted in - the database: - - 1. was_persisted() - Was the instance persisted in its old state. - 2. is_persisted() - Is the instance is_persisted in its current state. - - This schematic tries to illustrate how these methods relate to - each other:: - - - after create/save/delete after save/delete now - | | | - .-----------------------------------.----------------------------------. - |\ |\ |\ - | \ | \ | \ - | old_state() | previous_state() | current_state() - | | | - |-----------------------------------|----------------------------------| - | previous_changes() (prev - old) | changes() (cur - prev) | - |-----------------------------------|----------------------------------| - | old_changes() (cur - old) | - .----------------------------------------------------------------------. - \ \ - \ \ - was_persisted() is_persisted() - - """ def __init__(self, *args, **kwargs): - self._states = [] - - if not hasattr(self, '_data'): - self._data = {} - - if not 'id' in kwargs: - self._save_state(new_instance=True) - super(ChangesMixin, self).__init__(*args, **kwargs) - - if self.id: - self._save_state(new_instance=True) - signals.post_save.connect( _post_save, sender=self.__class__, # dispatch_uid='django-changes-%s' % self.__class__.__name__ From f232566204c655436e8b7ba17590c5b7bcc19e07 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 04:25:17 +0000 Subject: [PATCH 15/21] Complete re-write. --- django_model_changes/changes.py | 150 +++++--------------------------- 1 file changed, 21 insertions(+), 129 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 8bd2316..83a3fde 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -14,11 +14,9 @@ def __init__(self, *args, **kwargs): super(ChangesMixin, self).__init__(*args, **kwargs) signals.post_save.connect( _post_save, sender=self.__class__, - # dispatch_uid='django-changes-%s' % self.__class__.__name__ ) signals.post_delete.connect( _post_delete, sender=self.__class__, - # dispatch_uid='django-changes-%s' % self.__class__.__name__ ) def _save_state(self, new_instance=False, event_type='save', **kwargs): @@ -30,139 +28,33 @@ def _save_state(self, new_instance=False, event_type='save', **kwargs): if event_type == DELETE: self.pk = None - # Save current state. - self._states.append(self.current_state()) - - # Drop the previous old state - # _states == [previous old state, old state, previous state] - # ^^^^^^^^^^^^^^^^^^ - if len(self._states) > 2: - self._states.pop(0) - # Send post_change signal unless this is a new instance if not new_instance: - post_change.send(sender=self.__class__, instance=self, changes=self.old_changes(), **kwargs) - - def current_state(self): - """ - Returns a ``field -> value`` dict of the current state of the instance. - """ - def _try_copy(v): - if type(v) is DocumentProxy: - return v - if isinstance(v, (list, dict)): return copy.copy(v) # Shallow copy - return v - - # First level shallow copy. - return {k: _try_copy(v) for k, v in self._data.iteritems()} - - # The fastest but in-accurate version. - # return dict(self._data) - - def previous_state(self): - """ - Returns a ``field -> value`` dict of the state of the instance after it - was created, saved or deleted the previous time. - """ - if len(self._states) > 1: - return self._states[1] - else: - return self._states[0] - - def old_state(self): - """ - Returns a ``field -> value`` dict of the state of the instance after - it was created, saved or deleted the previous previous time. Returns - the previous state if there is no previous previous state. - """ - return self._states[0] + post_change.send(sender=self.__class__, instance=self, + changes=self._calculate_changes(**kwargs), + **kwargs) + + def _calculate_changes(self, created=False, _changed_fields=None, _original_values=None, **kwargs): + if _changed_fields is None: + _changed_fields = getattr(self, '_changed_fields', []) + if _original_values is None: + _original_values = getattr(self, '_original_values', {}) + + if created: + _changed_fields = self._data.keys() - def _changes(self, other, current): res = {} - for key in set(other.keys()) | set(current.keys()): - was, now = other.get(key), current.get(key) - if was != now: - res[key] = (was, now) - return res - - def changes(self): - """ - Returns a ``field -> (previous value, current value)`` dict of changes - from the previous state to the current state. - """ - return self._changes(self.previous_state(), self.current_state()) - - def old_changes(self): - """ - Returns a ``field -> (previous value, current value)`` dict of changes - from the old state to the current state. - """ - return self._changes(self.old_state(), self.current_state()) - - def previous_changes(self): - """ - Returns a ``field -> (previous value, current value)`` dict of changes - from the old state to the previous state. - """ - return self._changes(self.old_state(), self.previous_state()) - - def was_persisted(self): - """ - Returns true if the instance was persisted (saved) in its old - state. + for field in _changed_fields: + if field not in ["_id"]: + was = _original_values.get(field, None) + now = getattr(self, field, None) + if was != now: + res[field] = (was, now) - Examples:: - - >>> user = User() - >>> user.save() - >>> user.was_persisted() - False - - >>> user = User.objects.get(pk=1) - >>> user.delete() - >>> user.was_persisted() - True - """ - pk_name = self._meta.pk.name - return bool(self.old_state()[pk_name]) - - def is_persisted(self): - """ - Returns true if the instance is persisted (saved) in its current - state. - - Examples: - - >>> user = User() - >>> user.save() - >>> user.is_persisted() - True - - >>> user = User.objects.get(pk=1) - >>> user.delete() - >>> user.is_persisted() - False - """ - return bool(self.pk) - - def old_instance(self): - """ - Returns an instance of this model in its old state. - """ - return self.__class__(**self.old_state()) - - def previous_instance(self): - """ - Returns an instance of this model in its previous state. - """ - return self.__class__(**self.previous_state()) - - def reload(self, *args, **kwargs): - res = super(ChangesMixin, self).reload(*args, **kwargs) - self._states = [] - self._save_state(new_instance=True) return res - + + def changes(self): + return self._calculate_changes() def _post_save(sender, **kwargs): kwargs['document']._save_state(new_instance=False, event_type=SAVE, **kwargs) From 1b1320f793e665efbec34a27be36568af7e5663a Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 08:38:46 +0000 Subject: [PATCH 16/21] remove was not now check --- django_model_changes/changes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 83a3fde..4444cc8 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -48,8 +48,7 @@ def _calculate_changes(self, created=False, _changed_fields=None, _original_valu if field not in ["_id"]: was = _original_values.get(field, None) now = getattr(self, field, None) - if was != now: - res[field] = (was, now) + res[field] = (was, now) return res From a6e83e584aff2247a213e2db4af979291e4c6f91 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 22:38:43 +0000 Subject: [PATCH 17/21] register signals only once. --- django_model_changes/changes.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 4444cc8..c9522cd 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -12,12 +12,18 @@ class ChangesMixin(object): def __init__(self, *args, **kwargs): super(ChangesMixin, self).__init__(*args, **kwargs) - signals.post_save.connect( - _post_save, sender=self.__class__, - ) - signals.post_delete.connect( - _post_delete, sender=self.__class__, - ) + self.__class__.register_signals() + + @classmethod + def register_signals(cls): + if not getattr(cls, 'changes_signal_registered', False): + setattr(cls, 'changes_signal_registered', True) + signals.post_save.connect( + _post_save, sender=cls, + ) + signals.post_delete.connect( + _post_delete, sender=cls, + ) def _save_state(self, new_instance=False, event_type='save', **kwargs): if "Historical" in self.__class__.__name__: From 01e023e4c845dc661e461515f12d78d6f30907a2 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 22:47:01 +0000 Subject: [PATCH 18/21] Move signal registry to first save. --- django_model_changes/changes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index c9522cd..a313960 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -10,9 +10,9 @@ class ChangesMixin(object): - def __init__(self, *args, **kwargs): - super(ChangesMixin, self).__init__(*args, **kwargs) + def save(self, *args, **kwargs): self.__class__.register_signals() + return super(ChangesMixin, self).save(*args, **kwargs) @classmethod def register_signals(cls): From dac6db66116ca166156b4e02e7c9600956f5ecf0 Mon Sep 17 00:00:00 2001 From: Prasanna Sankaranarayanan Date: Thu, 5 Oct 2017 23:42:16 +0000 Subject: [PATCH 19/21] Fix for inherited classes. --- django_model_changes/changes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index a313960..878a6f1 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -16,8 +16,9 @@ def save(self, *args, **kwargs): @classmethod def register_signals(cls): - if not getattr(cls, 'changes_signal_registered', False): - setattr(cls, 'changes_signal_registered', True) + key = ('changes_signal_registered_%s' % cls.__name__) + if not getattr(cls, key, False): + setattr(cls, key, True) signals.post_save.connect( _post_save, sender=cls, ) From 4ba704547f5fac7df0acf321172852a34097c16b Mon Sep 17 00:00:00 2001 From: sauravshah Date: Tue, 22 Oct 2019 17:48:28 +0530 Subject: [PATCH 20/21] changes() should consider force_update_fields --- django_model_changes/changes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index 878a6f1..ae163f3 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -46,12 +46,14 @@ def _calculate_changes(self, created=False, _changed_fields=None, _original_valu _changed_fields = getattr(self, '_changed_fields', []) if _original_values is None: _original_values = getattr(self, '_original_values', {}) + + _force_changed_fields = getattr(self, '_force_changed_fields', set()) if created: _changed_fields = self._data.keys() res = {} - for field in _changed_fields: + for field in set(_changed_fields) | _force_changed_fields: if field not in ["_id"]: was = _original_values.get(field, None) now = getattr(self, field, None) From cf13cccc7b6a2510664ff3c332a5084adb5b8cac Mon Sep 17 00:00:00 2001 From: Miral Date: Mon, 10 Feb 2020 15:03:51 +0530 Subject: [PATCH 21/21] module migration --- django_model_changes/__init__.py | 4 ++-- django_model_changes/changes.py | 5 +++-- django_model_changes/signals.py | 1 + docs/source/conf.py | 1 + runtests.py | 1 + setup.py | 1 + tests/models.py | 1 + tests/tests.py | 1 + 8 files changed, 11 insertions(+), 4 deletions(-) diff --git a/django_model_changes/__init__.py b/django_model_changes/__init__.py index b6c912c..b51cbb4 100644 --- a/django_model_changes/__init__.py +++ b/django_model_changes/__init__.py @@ -1,2 +1,2 @@ -from changes import ChangesMixin -from signals import post_change +from django_model_changes.changes import ChangesMixin +from django_model_changes.signals import post_change diff --git a/django_model_changes/changes.py b/django_model_changes/changes.py index ae163f3..c21c24a 100644 --- a/django_model_changes/changes.py +++ b/django_model_changes/changes.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy from mongoengine import signals from mongoengine.base.proxy import DocumentProxy @@ -16,7 +17,7 @@ def save(self, *args, **kwargs): @classmethod def register_signals(cls): - key = ('changes_signal_registered_%s' % cls.__name__) + key = ('changes_signal_registered_{}'.format(cls.__name__)) if not getattr(cls, key, False): setattr(cls, key, True) signals.post_save.connect( @@ -50,7 +51,7 @@ def _calculate_changes(self, created=False, _changed_fields=None, _original_valu _force_changed_fields = getattr(self, '_force_changed_fields', set()) if created: - _changed_fields = self._data.keys() + _changed_fields = list(self._data.keys()) res = {} for field in set(_changed_fields) | _force_changed_fields: diff --git a/django_model_changes/signals.py b/django_model_changes/signals.py index a467746..ab51fa8 100644 --- a/django_model_changes/signals.py +++ b/django_model_changes/signals.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.dispatch import Signal diff --git a/docs/source/conf.py b/docs/source/conf.py index 8f03199..80ade91 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,6 +11,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import absolute_import import sys, os # If extensions (or django-model-changes to document with autodoc) are in another directory, diff --git a/runtests.py b/runtests.py index 180f4e7..b43f040 100644 --- a/runtests.py +++ b/runtests.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import absolute_import import sys import os from os.path import dirname, abspath diff --git a/setup.py b/setup.py index 29bb5d3..c71ec5d 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os from setuptools import setup, find_packages diff --git a/tests/models.py b/tests/models.py index a30f453..732c6b9 100644 --- a/tests/models.py +++ b/tests/models.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.db import models from django_model_changes.changes import ChangesMixin diff --git a/tests/tests.py b/tests/tests.py index 12806e5..5204fea 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from django.test import TestCase from .models import User, Article