From aa9452471b713f550705c567601c8ad235ca4103 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 9 Sep 2025 10:06:14 -0400 Subject: [PATCH 1/3] Extend update_object() to support non-field attribute assignment --- netbox_branching/utilities.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/netbox_branching/utilities.py b/netbox_branching/utilities.py index 30c2a27..3f63910 100644 --- a/netbox_branching/utilities.py +++ b/netbox_branching/utilities.py @@ -6,7 +6,7 @@ from functools import cached_property from django.contrib import messages -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist from django.db.models import ForeignKey, ManyToManyField from django.http import HttpResponseBadRequest from django.urls import reverse @@ -188,13 +188,16 @@ def update_object(instance, data, using): if attr == 'custom_fields': attr = 'custom_field_data' - model_field = instance._meta.get_field(attr) - field_cls = model_field.__class__ + try: + model_field = instance._meta.get_field(attr) + field_cls = model_field.__class__ + except FieldDoesNotExist: + field_cls = None - if issubclass(field_cls, ForeignKey): + if field_cls and issubclass(field_cls, ForeignKey): # Direct value assignment for ForeignKeys must be done by the field's concrete name setattr(instance, f'{attr}_id', value) - elif issubclass(field_cls, (ManyToManyField, TaggableManager)): + elif field_cls and issubclass(field_cls, (ManyToManyField, TaggableManager)): # Use M2M manager for ManyToMany assignments m2m_manager = getattr(instance, attr) m2m_assignments[m2m_manager] = value From 26b68cfbc3c9c9f01278e184aa35f2504635553f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 9 Sep 2025 10:06:55 -0400 Subject: [PATCH 2/3] Call a model's custom serialize_object() & deserialize_object() methods if defined --- netbox_branching/models/changes.py | 6 +++++- netbox_branching/signal_receivers.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/netbox_branching/models/changes.py b/netbox_branching/models/changes.py index 1d8606d..68e91a0 100644 --- a/netbox_branching/models/changes.py +++ b/netbox_branching/models/changes.py @@ -48,7 +48,10 @@ def apply(self, branch, using=DEFAULT_DB_ALIAS, logger=None): # Creating a new object if self.action == ObjectChangeActionChoices.ACTION_CREATE: - instance = deserialize_object(model, self.postchange_data, pk=self.changed_object_id) + if hasattr(model, 'deserialize_object'): + instance = model.deserialize_object(self.postchange_data, pk=self.changed_object_id) + else: + instance = deserialize_object(model, self.postchange_data, pk=self.changed_object_id) logger.debug(f'Creating {model._meta.verbose_name} {instance}') instance.object.full_clean() instance.save(using=using) @@ -56,6 +59,7 @@ def apply(self, branch, using=DEFAULT_DB_ALIAS, logger=None): # Modifying an object elif self.action == ObjectChangeActionChoices.ACTION_UPDATE: instance = model.objects.using(using).get(pk=self.changed_object_id) + logger.debug(f'Updating {model._meta.verbose_name} {instance}') update_object(instance, self.diff()['post'], using=using) # Deleting an object diff --git a/netbox_branching/signal_receivers.py b/netbox_branching/signal_receivers.py index ea27f8a..23621ec 100644 --- a/netbox_branching/signal_receivers.py +++ b/netbox_branching/signal_receivers.py @@ -81,7 +81,10 @@ def record_change_diff(instance, **kwargs): model = instance.changed_object_type.model_class() with deactivate_branch(): obj = model.objects.get(pk=instance.changed_object_id) - current_data = serialize_object(obj, exclude=['created', 'last_updated']) + if hasattr(obj, 'serialize_object'): + current_data = obj.serialize_object(exclude=['created', 'last_updated']) + else: + current_data = serialize_object(obj, exclude=['created', 'last_updated']) diff = ChangeDiff( branch=branch, object=instance.changed_object, From 609372e1c8f075863b847ee2615a7633e39d84c5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 10 Sep 2025 12:56:39 -0400 Subject: [PATCH 3/3] Bump minimum NetBox version to 4.4.1 --- netbox_branching/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_branching/__init__.py b/netbox_branching/__init__.py index 7f30d9f..398b587 100644 --- a/netbox_branching/__init__.py +++ b/netbox_branching/__init__.py @@ -14,7 +14,7 @@ class AppConfig(PluginConfig): description = 'A git-like branching implementation for NetBox' version = '0.7.0' base_url = 'branching' - min_version = '4.4.0' + min_version = '4.4.1' max_version = '4.4.99' middleware = [ 'netbox_branching.middleware.BranchMiddleware'