Sfoglia il codice sorgente

Fixes #19987: Show changelog_message field only for models which support change logging

Jeremy Stretch 6 mesi fa
parent
commit
ae425d9da9

+ 2 - 2
netbox/dcim/forms/bulk_edit.py

@@ -11,7 +11,7 @@ from ipam.choices import VLANQinQRoleChoices
 from ipam.models import ASN, VLAN, VLANGroup, VRF
 from ipam.models import ASN, VLAN, VLANGroup, VRF
 from netbox.choices import *
 from netbox.choices import *
 from netbox.forms import NetBoxModelBulkEditForm
 from netbox.forms import NetBoxModelBulkEditForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from users.models import User
 from users.models import User
 from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
 from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
@@ -1038,7 +1038,7 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
 # Device component templates
 # Device component templates
 #
 #
 
 
-class ComponentTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ComponentTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pass
     pass
 
 
 
 

+ 2 - 2
netbox/dcim/forms/model_forms.py

@@ -11,7 +11,7 @@ from extras.models import ConfigTemplate
 from ipam.choices import VLANQinQRoleChoices
 from ipam.choices import VLANQinQRoleChoices
 from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VLANTranslationPolicy, VRF
 from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VLANTranslationPolicy, VRF
 from netbox.forms import NetBoxModelForm
 from netbox.forms import NetBoxModelForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from users.models import User
 from users.models import User
 from utilities.forms import add_blank_choice, get_field_value
 from utilities.forms import add_blank_choice, get_field_value
@@ -974,7 +974,7 @@ class VCMemberSelectForm(forms.Form):
 # Device component templates
 # Device component templates
 #
 #
 
 
-class ComponentTemplateForm(ChangeLoggingMixin, forms.ModelForm):
+class ComponentTemplateForm(ChangelogMessageMixin, forms.ModelForm):
     device_type = DynamicModelChoiceField(
     device_type = DynamicModelChoiceField(
         label=_('Device type'),
         label=_('Device type'),
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),

+ 11 - 11
netbox/extras/forms/bulk_edit.py

@@ -5,7 +5,7 @@ from extras.choices import *
 from extras.models import *
 from extras.models import *
 from netbox.events import get_event_type_choices
 from netbox.events import get_event_type_choices
 from netbox.forms import NetBoxModelBulkEditForm
 from netbox.forms import NetBoxModelBulkEditForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from utilities.forms import BulkEditForm, add_blank_choice
 from utilities.forms import BulkEditForm, add_blank_choice
 from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField
 from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField
 from utilities.forms.rendering import FieldSet
 from utilities.forms.rendering import FieldSet
@@ -28,7 +28,7 @@ __all__ = (
 )
 )
 
 
 
 
-class CustomFieldBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomField.objects.all(),
         queryset=CustomField.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -96,7 +96,7 @@ class CustomFieldBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('group_name', 'description', 'choice_set')
     nullable_fields = ('group_name', 'description', 'choice_set')
 
 
 
 
-class CustomFieldChoiceSetBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomFieldChoiceSet.objects.all(),
         queryset=CustomFieldChoiceSet.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -116,7 +116,7 @@ class CustomFieldChoiceSetBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('base_choices', 'description')
     nullable_fields = ('base_choices', 'description')
 
 
 
 
-class CustomLinkBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=CustomLink.objects.all(),
         queryset=CustomLink.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -142,7 +142,7 @@ class CustomLinkBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     )
     )
 
 
 
 
-class ExportTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ExportTemplate.objects.all(),
         queryset=ExportTemplate.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -175,7 +175,7 @@ class ExportTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
 
 
 
 
-class SavedFilterBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class SavedFilterBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=SavedFilter.objects.all(),
         queryset=SavedFilter.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -295,7 +295,7 @@ class EventRuleBulkEditForm(NetBoxModelBulkEditForm):
     nullable_fields = ('description', 'conditions')
     nullable_fields = ('description', 'conditions')
 
 
 
 
-class TagBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -317,7 +317,7 @@ class TagBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description',)
     nullable_fields = ('description',)
 
 
 
 
-class ConfigContextBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ConfigContext.objects.all(),
         queryset=ConfigContext.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -341,7 +341,7 @@ class ConfigContextBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description',)
     nullable_fields = ('description',)
 
 
 
 
-class ConfigTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class ConfigTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ConfigTemplate.objects.all(),
         queryset=ConfigTemplate.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -374,7 +374,7 @@ class ConfigTemplateBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
     nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
 
 
 
 
-class JournalEntryBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class JournalEntryBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=JournalEntry.objects.all(),
         queryset=JournalEntry.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -387,7 +387,7 @@ class JournalEntryBulkEditForm(ChangeLoggingMixin, BulkEditForm):
     comments = CommentField()
     comments = CommentField()
 
 
 
 
-class NotificationGroupBulkEditForm(ChangeLoggingMixin, BulkEditForm):
+class NotificationGroupBulkEditForm(ChangelogMessageMixin, BulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=NotificationGroup.objects.all(),
         queryset=NotificationGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput

+ 10 - 10
netbox/extras/forms/model_forms.py

@@ -13,7 +13,7 @@ from extras.choices import *
 from extras.models import *
 from extras.models import *
 from netbox.events import get_event_type_choices
 from netbox.events import get_event_type_choices
 from netbox.forms import NetBoxModelForm
 from netbox.forms import NetBoxModelForm
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
 from users.models import Group, User
 from users.models import Group, User
 from utilities.forms import get_field_value
 from utilities.forms import get_field_value
@@ -46,7 +46,7 @@ __all__ = (
 )
 )
 
 
 
 
-class CustomFieldForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('custom_fields'),
         queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -165,7 +165,7 @@ class CustomFieldForm(ChangeLoggingMixin, forms.ModelForm):
             del self.fields['choice_set']
             del self.fields['choice_set']
 
 
 
 
-class CustomFieldChoiceSetForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
     # TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model
     # TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model
     extra_choices = forms.CharField(
     extra_choices = forms.CharField(
         widget=ChoicesWidget(),
         widget=ChoicesWidget(),
@@ -218,7 +218,7 @@ class CustomFieldChoiceSetForm(ChangeLoggingMixin, forms.ModelForm):
         return data
         return data
 
 
 
 
-class CustomLinkForm(ChangeLoggingMixin, forms.ModelForm):
+class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('custom_links')
         queryset=ObjectType.objects.with_feature('custom_links')
@@ -250,7 +250,7 @@ class CustomLinkForm(ChangeLoggingMixin, forms.ModelForm):
         }
         }
 
 
 
 
-class ExportTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     object_types = ContentTypeMultipleChoiceField(
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
         queryset=ObjectType.objects.with_feature('export_templates')
         queryset=ObjectType.objects.with_feature('export_templates')
@@ -292,7 +292,7 @@ class ExportTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
         return self.cleaned_data
         return self.cleaned_data
 
 
 
 
-class SavedFilterForm(ChangeLoggingMixin, forms.ModelForm):
+class SavedFilterForm(ChangelogMessageMixin, forms.ModelForm):
     slug = SlugField()
     slug = SlugField()
     object_types = ContentTypeMultipleChoiceField(
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
@@ -389,7 +389,7 @@ class BookmarkForm(forms.ModelForm):
         fields = ('object_type', 'object_id')
         fields = ('object_type', 'object_id')
 
 
 
 
-class NotificationGroupForm(ChangeLoggingMixin, forms.ModelForm):
+class NotificationGroupForm(ChangelogMessageMixin, forms.ModelForm):
     groups = DynamicModelMultipleChoiceField(
     groups = DynamicModelMultipleChoiceField(
         label=_('Groups'),
         label=_('Groups'),
         required=False,
         required=False,
@@ -562,7 +562,7 @@ class EventRuleForm(NetBoxModelForm):
         return self.cleaned_data
         return self.cleaned_data
 
 
 
 
-class TagForm(ChangeLoggingMixin, forms.ModelForm):
+class TagForm(ChangelogMessageMixin, forms.ModelForm):
     slug = SlugField()
     slug = SlugField()
     object_types = ContentTypeMultipleChoiceField(
     object_types = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
@@ -585,7 +585,7 @@ class TagForm(ChangeLoggingMixin, forms.ModelForm):
         ]
         ]
 
 
 
 
-class ConfigContextForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     regions = DynamicModelMultipleChoiceField(
     regions = DynamicModelMultipleChoiceField(
         label=_('Regions'),
         label=_('Regions'),
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -697,7 +697,7 @@ class ConfigContextForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
         return self.cleaned_data
         return self.cleaned_data
 
 
 
 
-class ConfigTemplateForm(ChangeLoggingMixin, SyncedDataMixin, forms.ModelForm):
+class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         label=_('Tags'),
         label=_('Tags'),
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),

+ 3 - 3
netbox/netbox/forms/base.py

@@ -11,7 +11,7 @@ from extras.models import CustomField, Tag
 from utilities.forms import BulkEditForm, CSVModelForm
 from utilities.forms import BulkEditForm, CSVModelForm
 from utilities.forms.fields import CSVModelMultipleChoiceField, DynamicModelMultipleChoiceField
 from utilities.forms.fields import CSVModelMultipleChoiceField, DynamicModelMultipleChoiceField
 from utilities.forms.mixins import CheckLastUpdatedMixin
 from utilities.forms.mixins import CheckLastUpdatedMixin
-from .mixins import ChangeLoggingMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin
+from .mixins import ChangelogMessageMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin
 
 
 __all__ = (
 __all__ = (
     'NetBoxModelForm',
     'NetBoxModelForm',
@@ -21,7 +21,7 @@ __all__ = (
 )
 )
 
 
 
 
-class NetBoxModelForm(ChangeLoggingMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm):
+class NetBoxModelForm(ChangelogMessageMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm):
     """
     """
     Base form for creating & editing NetBox models. Extends Django's ModelForm to add support for custom fields.
     Base form for creating & editing NetBox models. Extends Django's ModelForm to add support for custom fields.
 
 
@@ -100,7 +100,7 @@ class NetBoxModelImportForm(CSVModelForm, NetBoxModelForm):
         return customfield.to_form_field(for_csv_import=True)
         return customfield.to_form_field(for_csv_import=True)
 
 
 
 
-class NetBoxModelBulkEditForm(ChangeLoggingMixin, CustomFieldsMixin, BulkEditForm):
+class NetBoxModelBulkEditForm(ChangelogMessageMixin, CustomFieldsMixin, BulkEditForm):
     """
     """
     Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
     Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
     fields and adding/removing tags.
     fields and adding/removing tags.

+ 2 - 2
netbox/netbox/forms/mixins.py

@@ -7,14 +7,14 @@ from extras.models import *
 from utilities.forms.fields import DynamicModelMultipleChoiceField
 from utilities.forms.fields import DynamicModelMultipleChoiceField
 
 
 __all__ = (
 __all__ = (
-    'ChangeLoggingMixin',
+    'ChangelogMessageMixin',
     'CustomFieldsMixin',
     'CustomFieldsMixin',
     'SavedFiltersMixin',
     'SavedFiltersMixin',
     'TagsMixin',
     'TagsMixin',
 )
 )
 
 
 
 
-class ChangeLoggingMixin(forms.Form):
+class ChangelogMessageMixin(forms.Form):
     """
     """
     Adds an optional field for recording a message on the resulting changelog record(s).
     Adds an optional field for recording a message on the resulting changelog record(s).
     """
     """

+ 3 - 16
netbox/netbox/views/generic/bulk_views.py

@@ -21,14 +21,12 @@ from core.models import ObjectType
 from core.signals import clear_events
 from core.signals import clear_events
 from extras.choices import CustomFieldUIEditableChoices
 from extras.choices import CustomFieldUIEditableChoices
 from extras.models import CustomField, ExportTemplate
 from extras.models import CustomField, ExportTemplate
-from netbox.forms.mixins import ChangeLoggingMixin
 from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename
 from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename
 from utilities.error_handlers import handle_protectederror
 from utilities.error_handlers import handle_protectederror
 from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
 from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
 from utilities.export import TableExport
 from utilities.export import TableExport
-from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
+from utilities.forms import BulkDeleteForm, BulkRenameForm, restrict_form_fields
 from utilities.forms.bulk_import import BulkImportForm
 from utilities.forms.bulk_import import BulkImportForm
-from utilities.forms.mixins import BackgroundJobMixin
 from utilities.htmx import htmx_partial
 from utilities.htmx import htmx_partial
 from utilities.jobs import AsyncJobData, is_background_request, process_request_as_job
 from utilities.jobs import AsyncJobData, is_background_request, process_request_as_job
 from utilities.permissions import get_permission_for_model
 from utilities.permissions import get_permission_for_model
@@ -896,15 +894,6 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
     def get_required_permission(self):
     def get_required_permission(self):
         return get_permission_for_model(self.queryset.model, 'delete')
         return get_permission_for_model(self.queryset.model, 'delete')
 
 
-    def get_form(self):
-        """
-        Provide a standard bulk delete form if none has been specified for the view
-        """
-        class BulkDeleteForm(BackgroundJobMixin, ChangeLoggingMixin, ConfirmationForm):
-            pk = ModelMultipleChoiceField(queryset=self.queryset, widget=MultipleHiddenInput)
-
-        return BulkDeleteForm
-
     #
     #
     # Request handlers
     # Request handlers
     #
     #
@@ -925,10 +914,8 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
         else:
         else:
             pk_list = [int(pk) for pk in request.POST.getlist('pk')]
             pk_list = [int(pk) for pk in request.POST.getlist('pk')]
 
 
-        form_cls = self.get_form()
-
         if '_confirm' in request.POST:
         if '_confirm' in request.POST:
-            form = form_cls(request.POST)
+            form = BulkDeleteForm(model, request.POST)
             if form.is_valid():
             if form.is_valid():
                 logger.debug("Form validation was successful")
                 logger.debug("Form validation was successful")
 
 
@@ -990,7 +977,7 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView):
                 logger.debug("Form validation failed")
                 logger.debug("Form validation failed")
 
 
         else:
         else:
-            form = form_cls(initial={
+            form = BulkDeleteForm(model, initial={
                 'pk': pk_list,
                 'pk': pk_list,
                 'return_url': self.get_return_url(request),
                 'return_url': self.get_return_url(request),
             })
             })

+ 2 - 2
netbox/netbox/views/generic/object_views.py

@@ -425,7 +425,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
             request: The current request
             request: The current request
         """
         """
         obj = self.get_object(**kwargs)
         obj = self.get_object(**kwargs)
-        form = DeleteForm(initial=request.GET)
+        form = DeleteForm(instance=obj, initial=request.GET)
 
 
         try:
         try:
             dependent_objects = self._get_dependent_objects(obj)
             dependent_objects = self._get_dependent_objects(obj)
@@ -464,7 +464,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
         """
         """
         logger = logging.getLogger('netbox.views.ObjectDeleteView')
         logger = logging.getLogger('netbox.views.ObjectDeleteView')
         obj = self.get_object(**kwargs)
         obj = self.get_object(**kwargs)
-        form = DeleteForm(request.POST)
+        form = DeleteForm(request.POST, instance=obj)
 
 
         if form.is_valid():
         if form.is_valid():
             logger.debug("Form validation was successful")
             logger.debug("Form validation was successful")

+ 2 - 2
netbox/utilities/forms/bulk_import.py

@@ -8,13 +8,13 @@ from django.utils.translation import gettext as _
 
 
 from core.forms.mixins import SyncedDataMixin
 from core.forms.mixins import SyncedDataMixin
 from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, ImportMethodChoices
 from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, ImportMethodChoices
-from netbox.forms.mixins import ChangeLoggingMixin
+from netbox.forms.mixins import ChangelogMessageMixin
 from utilities.constants import CSV_DELIMITERS
 from utilities.constants import CSV_DELIMITERS
 from utilities.forms.mixins import BackgroundJobMixin
 from utilities.forms.mixins import BackgroundJobMixin
 from utilities.forms.utils import parse_csv
 from utilities.forms.utils import parse_csv
 
 
 
 
-class BulkImportForm(ChangeLoggingMixin, BackgroundJobMixin, SyncedDataMixin, forms.Form):
+class BulkImportForm(ChangelogMessageMixin, BackgroundJobMixin, SyncedDataMixin, forms.Form):
     import_method = forms.ChoiceField(
     import_method = forms.ChoiceField(
         choices=ImportMethodChoices,
         choices=ImportMethodChoices,
         required=False
         required=False

+ 29 - 0
netbox/utilities/forms/forms.py

@@ -3,9 +3,11 @@ import re
 from django import forms
 from django import forms
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
+from netbox.models.features import ChangeLoggingMixin
 from utilities.forms.mixins import BackgroundJobMixin
 from utilities.forms.mixins import BackgroundJobMixin
 
 
 __all__ = (
 __all__ = (
+    'BulkDeleteForm',
     'BulkEditForm',
     'BulkEditForm',
     'BulkRenameForm',
     'BulkRenameForm',
     'ConfirmationForm',
     'ConfirmationForm',
@@ -40,6 +42,13 @@ class DeleteForm(ConfirmationForm):
         max_length=200
         max_length=200
     )
     )
 
 
+    def __init__(self, *args, instance=None, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # Hide the changelog_message filed if the model doesn't support change logging
+        if instance is None or not issubclass(instance._meta.model, ChangeLoggingMixin):
+            self.fields.pop('changelog_message')
+
 
 
 class BulkEditForm(BackgroundJobMixin, forms.Form):
 class BulkEditForm(BackgroundJobMixin, forms.Form):
     """
     """
@@ -81,6 +90,26 @@ class BulkRenameForm(forms.Form):
                 })
                 })
 
 
 
 
+class BulkDeleteForm(BackgroundJobMixin, ConfirmationForm):
+    pk = forms.ModelMultipleChoiceField(
+        queryset=None,
+        widget=forms.MultipleHiddenInput
+    )
+    changelog_message = forms.CharField(
+        required=False,
+        max_length=200
+    )
+
+    def __init__(self, model, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        self.fields['pk'].queryset = model.objects.all()
+
+        # Hide the changelog_message filed if the model doesn't support change logging
+        if model is None or not issubclass(model, ChangeLoggingMixin):
+            self.fields.pop('changelog_message')
+
+
 class CSVModelForm(forms.ModelForm):
 class CSVModelForm(forms.ModelForm):
     """
     """
     ModelForm used for the import of objects in CSV format.
     ModelForm used for the import of objects in CSV format.