From 8d5436876ed2ef7c5321864b689d7edd1fc87de5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 17 Jul 2025 16:37:42 -0400 Subject: [PATCH] Enable changelog messages for single object operations --- netbox/netbox/forms/base.py | 4 ++-- netbox/netbox/forms/mixins.py | 15 +++++++++++++++ netbox/netbox/models/features.py | 5 ++++- netbox/netbox/views/generic/object_views.py | 7 ++++--- netbox/templates/htmx/form.html | 4 ++++ netbox/utilities/forms/forms.py | 11 +++++++++++ 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 57cfd1801..c09e8f7fd 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -11,7 +11,7 @@ from extras.models import CustomField, Tag from utilities.forms import BulkEditForm, CSVModelForm from utilities.forms.fields import CSVModelMultipleChoiceField, DynamicModelMultipleChoiceField from utilities.forms.mixins import CheckLastUpdatedMixin -from .mixins import CustomFieldsMixin, SavedFiltersMixin, TagsMixin +from .mixins import ChangeLoggingMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin __all__ = ( 'NetBoxModelForm', @@ -21,7 +21,7 @@ __all__ = ( ) -class NetBoxModelForm(CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm): +class NetBoxModelForm(ChangeLoggingMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm): """ Base form for creating & editing NetBox models. Extends Django's ModelForm to add support for custom fields. diff --git a/netbox/netbox/forms/mixins.py b/netbox/netbox/forms/mixins.py index c569343ee..b06487141 100644 --- a/netbox/netbox/forms/mixins.py +++ b/netbox/netbox/forms/mixins.py @@ -7,12 +7,27 @@ from extras.models import * from utilities.forms.fields import DynamicModelMultipleChoiceField __all__ = ( + 'ChangeLoggingMixin', 'CustomFieldsMixin', 'SavedFiltersMixin', 'TagsMixin', ) +class ChangeLoggingMixin(forms.Form): + changelog_message = forms.CharField( + required=False, + max_length=200 + ) + + def clean(self): + + # Attach the changelog message (if any) to the instance + self.instance._changelog_message = self.cleaned_data.pop('changelog_message', None) + + return self.cleaned_data + + class CustomFieldsMixin: """ Extend a Form to include custom field support. diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 79145ce70..023259cc8 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -63,6 +63,8 @@ class ChangeLoggingMixin(DeleteMixin, models.Model): null=True ) + _changelog_message = None + class Meta: abstract = True @@ -103,7 +105,8 @@ class ChangeLoggingMixin(DeleteMixin, models.Model): objectchange = ObjectChange( changed_object=self, object_repr=str(self)[:200], - action=action + action=action, + message=self._changelog_message or '', ) if hasattr(self, '_prechange_snapshot'): objectchange.prechange_data = self._prechange_snapshot diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 5bc79d962..a8c50c1c4 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -19,7 +19,7 @@ from netbox.object_actions import ( ) from utilities.error_handlers import handle_protectederror from utilities.exceptions import AbortRequest, PermissionsViolation -from utilities.forms import ConfirmationForm, restrict_form_fields +from utilities.forms import DeleteForm, restrict_form_fields from utilities.htmx import htmx_partial from utilities.permissions import get_permission_for_model from utilities.querydict import normalize_querydict, prepare_cloned_fields @@ -422,7 +422,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): request: The current request """ obj = self.get_object(**kwargs) - form = ConfirmationForm(initial=request.GET) + form = DeleteForm(initial=request.GET) try: dependent_objects = self._get_dependent_objects(obj) @@ -461,7 +461,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): """ logger = logging.getLogger('netbox.views.ObjectDeleteView') obj = self.get_object(**kwargs) - form = ConfirmationForm(request.POST) + form = DeleteForm(request.POST) # Take a snapshot of change-logged models if hasattr(obj, 'snapshot'): @@ -469,6 +469,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): if form.is_valid(): logger.debug("Form validation was successful") + obj._changelog_message = form.cleaned_data.pop('changelog_message', '') try: obj.delete() diff --git a/netbox/templates/htmx/form.html b/netbox/templates/htmx/form.html index 530a18054..1108a6113 100644 --- a/netbox/templates/htmx/form.html +++ b/netbox/templates/htmx/form.html @@ -28,6 +28,10 @@ {% endif %} + {% if form.changelog_message %} + {% render_field form.changelog_message %} + {% endif %} + {% else %} {# Render all fields in a single group #} diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py index 2192c5a99..122107728 100644 --- a/netbox/utilities/forms/forms.py +++ b/netbox/utilities/forms/forms.py @@ -10,6 +10,7 @@ __all__ = ( 'BulkRenameForm', 'ConfirmationForm', 'CSVModelForm', + 'DeleteForm', 'FilterForm', 'TableConfigForm', ) @@ -30,6 +31,16 @@ class ConfirmationForm(forms.Form): ) +class DeleteForm(ConfirmationForm): + """ + Confirm the deletion of an object, optionally providing a changelog message. + """ + changelog_message = forms.CharField( + required=False, + max_length=200 + ) + + class BulkEditForm(BackgroundJobMixin, forms.Form): """ Provides bulk edit support for objects.