diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 0e224c6d0..4dc775364 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -239,8 +239,7 @@ class CircuitTermination( raise ValidationError("A circuit termination cannot attach to both a site and a provider network.") def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.circuit return objectchange diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index 4048a091a..90bf9501f 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -386,8 +386,7 @@ class CableTermination(ChangeLoggedModel): cache_related_objects.alters_data = True def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.termination return objectchange diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index b56a55aed..dacd7ec3e 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -91,8 +91,7 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin): self._original_device_type = self.__dict__.get('device_type_id') def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.device_type return objectchange @@ -139,8 +138,7 @@ class ModularComponentTemplateModel(ComponentTemplateModel): ) def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) if self.device_type is not None: objectchange.related_object = self.device_type elif self.module_type is not None: diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 39a98a302..ef235078f 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -93,8 +93,7 @@ class ComponentModel(NetBoxModel): return self.name def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.device return objectchange diff --git a/netbox/extras/models/change_logging.py b/netbox/extras/models/change_logging.py index 7befed095..0155849aa 100644 --- a/netbox/extras/models/change_logging.py +++ b/netbox/extras/models/change_logging.py @@ -135,3 +135,7 @@ class ObjectChange(models.Model): def get_action_color(self): return ObjectChangeActionChoices.colors.get(self.action) + + @property + def has_changes(self): + return self.prechange_data != self.postchange_data diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index bcbfb1aa9..d49536c58 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -688,8 +688,7 @@ class ImageAttachment(ChangeLoggedModel): return None def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.parent return objectchange diff --git a/netbox/extras/signals.py b/netbox/extras/signals.py index 2f463dd5c..da0b635ff 100644 --- a/netbox/extras/signals.py +++ b/netbox/extras/signals.py @@ -80,7 +80,7 @@ def handle_changed_object(sender, instance, **kwargs): ) else: objectchange = instance.to_objectchange(action) - if objectchange: + if objectchange and objectchange.has_changes: objectchange.user = request.user objectchange.request_id = request.id objectchange.save() diff --git a/netbox/extras/tests/test_changelog.py b/netbox/extras/tests/test_changelog.py index cfb2e5d04..651eab453 100644 --- a/netbox/extras/tests/test_changelog.py +++ b/netbox/extras/tests/test_changelog.py @@ -208,6 +208,7 @@ class ChangeLogViewTest(ModelViewTestCase): self.assertEqual(objectchange.prechange_data['slug'], sites[0].slug) self.assertEqual(objectchange.postchange_data, None) + @override_settings(CHANGELOG_SKIP_EMPTY_CHANGES=False) def test_update_object_change(self): site = Site( name='Site 1', diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index d0d0fe475..adf130ad7 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -902,8 +902,7 @@ class IPAddress(PrimaryModel): return attrs def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.assigned_object return objectchange diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 571327fe4..d843f3c63 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -94,14 +94,6 @@ class ChangeLoggingMixin(models.Model): if get_config().CHANGELOG_SKIP_EMPTY_CHANGES: exclude_fields = ['last_updated',] - postchange_data = None - if action in (ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE): - postchange_data = self.serialize_object(exclude_fields=exclude_fields) - - if get_config().CHANGELOG_SKIP_EMPTY_CHANGES and action == ObjectChangeActionChoices.ACTION_UPDATE and hasattr(self, '_prechange_snapshot'): - if postchange_data == self._prechange_snapshot: - return None - objectchange = ObjectChange( changed_object=self, object_repr=str(self)[:200], @@ -110,7 +102,7 @@ class ChangeLoggingMixin(models.Model): if hasattr(self, '_prechange_snapshot'): objectchange.prechange_data = self._prechange_snapshot if action in (ObjectChangeActionChoices.ACTION_CREATE, ObjectChangeActionChoices.ACTION_UPDATE): - objectchange.postchange_data = postchange_data + objectchange.postchange_data = self.serialize_object(exclude_fields=exclude_fields) return objectchange diff --git a/netbox/tenancy/models/contacts.py b/netbox/tenancy/models/contacts.py index 55f267dea..81e11a7dd 100644 --- a/netbox/tenancy/models/contacts.py +++ b/netbox/tenancy/models/contacts.py @@ -171,7 +171,6 @@ class ContactAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, Chan ) def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.object return objectchange diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index f01ad6014..233d51d63 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -298,8 +298,7 @@ class ComponentModel(NetBoxModel): return self.name def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.virtual_machine return objectchange diff --git a/netbox/vpn/models/tunnels.py b/netbox/vpn/models/tunnels.py index dbe17e2a8..be1e40142 100644 --- a/netbox/vpn/models/tunnels.py +++ b/netbox/vpn/models/tunnels.py @@ -178,7 +178,6 @@ class TunnelTermination(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ChangeLo }) def to_objectchange(self, action): - if (objectchange := super().to_objectchange(action)) is None: - return None + objectchange = super().to_objectchange(action) objectchange.related_object = self.tunnel return objectchange