From 3621b1a0d09a52996c72e5c7c14a502214b0362a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 1 Feb 2022 11:00:18 -0500 Subject: [PATCH] Set model as attribute on bulk edit forms --- netbox/circuits/forms/bulk_edit.py | 4 +++ netbox/dcim/forms/bulk_edit.py | 30 +++++++++++++++++++++++ netbox/extras/forms/customfields.py | 7 +++++- netbox/ipam/forms/bulk_edit.py | 13 ++++++++++ netbox/netbox/forms/base.py | 6 +++-- netbox/netbox/views/generic/bulk_views.py | 4 +-- netbox/tenancy/forms/bulk_edit.py | 5 ++++ netbox/utilities/forms/forms.py | 19 ++++---------- netbox/virtualization/forms/bulk_edit.py | 5 ++++ netbox/wireless/forms/bulk_edit.py | 3 +++ 10 files changed, 77 insertions(+), 19 deletions(-) diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py index 9c20a2fe7..43419a871 100644 --- a/netbox/circuits/forms/bulk_edit.py +++ b/netbox/circuits/forms/bulk_edit.py @@ -47,6 +47,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = Provider nullable_fields = ( 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', ) @@ -74,6 +75,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = ProviderNetwork nullable_fields = ( 'service_id', 'description', 'comments', ) @@ -89,6 +91,7 @@ class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = CircuitType nullable_fields = ('description',) @@ -128,6 +131,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = Circuit nullable_fields = ( 'tenant', 'commit_rate', 'description', 'comments', ) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index a126d22f9..c7fbcf3f1 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -71,6 +71,7 @@ class RegionBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Region nullable_fields = ('parent', 'description') @@ -88,6 +89,7 @@ class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = SiteGroup nullable_fields = ('parent', 'description') @@ -129,6 +131,7 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): widget=StaticSelect() ) + model = Site nullable_fields = ( 'region', 'group', 'tenant', 'asns', 'description', 'time_zone', ) @@ -159,6 +162,7 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Location nullable_fields = ('parent', 'tenant', 'description') @@ -175,6 +179,7 @@ class RackRoleBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = RackRole nullable_fields = ('color', 'description') @@ -272,6 +277,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = Rack nullable_fields = ( 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments', ) @@ -298,6 +304,8 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = RackReservation + class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): pk = forms.ModelMultipleChoiceField( @@ -309,6 +317,7 @@ class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Manufacturer nullable_fields = ('description',) @@ -339,6 +348,7 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): widget=StaticSelect() ) + model = DeviceType nullable_fields = ('part_number', 'airflow') @@ -355,6 +365,7 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ModuleType nullable_fields = ('part_number',) @@ -376,6 +387,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = DeviceRole nullable_fields = ('color', 'description') @@ -398,6 +410,7 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Platform nullable_fields = ('manufacturer', 'napalm_driver', 'description') @@ -456,6 +469,7 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): label='Serial Number' ) + model = Device nullable_fields = ( 'tenant', 'platform', 'serial', 'airflow', ) @@ -483,6 +497,7 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): label='Serial Number' ) + model = Module nullable_fields = ('serial',) @@ -525,6 +540,7 @@ class CableBulkEditForm(NetBoxModelBulkEditForm): widget=StaticSelect() ) + model = Cable nullable_fields = ( 'type', 'status', 'tenant', 'label', 'color', 'length', ) @@ -551,6 +567,7 @@ class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = VirtualChassis nullable_fields = ('domain',) @@ -589,6 +606,7 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): } ) + model = PowerPanel nullable_fields = ('location',) @@ -647,6 +665,7 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = PowerFeed nullable_fields = ('location', 'comments') @@ -918,6 +937,7 @@ class ConsolePortBulkEditForm( widget=BulkEditNullBooleanSelect ) + model = ConsolePort nullable_fields = ('label', 'description') @@ -934,6 +954,7 @@ class ConsoleServerPortBulkEditForm( widget=BulkEditNullBooleanSelect ) + model = ConsoleServerPort nullable_fields = ('label', 'description') @@ -950,6 +971,7 @@ class PowerPortBulkEditForm( widget=BulkEditNullBooleanSelect ) + model = PowerPort nullable_fields = ('label', 'description') @@ -972,6 +994,7 @@ class PowerOutletBulkEditForm( widget=BulkEditNullBooleanSelect ) + model = PowerOutlet nullable_fields = ('label', 'type', 'feed_leg', 'power_port', 'description') def __init__(self, *args, **kwargs): @@ -1051,6 +1074,7 @@ class InterfaceBulkEditForm( label='VRF' ) + model = Interface nullable_fields = ( 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'description', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan', 'tagged_vlans', 'vrf', @@ -1119,6 +1143,7 @@ class FrontPortBulkEditForm( widget=forms.MultipleHiddenInput() ) + model = FrontPort nullable_fields = ('label', 'description') @@ -1131,6 +1156,7 @@ class RearPortBulkEditForm( widget=forms.MultipleHiddenInput() ) + model = RearPort nullable_fields = ('label', 'description') @@ -1143,6 +1169,7 @@ class ModuleBayBulkEditForm( widget=forms.MultipleHiddenInput() ) + model = ModuleBay nullable_fields = ('label', 'position', 'description') @@ -1155,6 +1182,7 @@ class DeviceBayBulkEditForm( widget=forms.MultipleHiddenInput() ) + model = DeviceBay nullable_fields = ('label', 'description') @@ -1175,6 +1203,7 @@ class InventoryItemBulkEditForm( required=False ) + model = InventoryItem nullable_fields = ('label', 'role', 'manufacturer', 'part_id', 'description') @@ -1195,4 +1224,5 @@ class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = InventoryItemRole nullable_fields = ('color', 'description') diff --git a/netbox/extras/forms/customfields.py b/netbox/extras/forms/customfields.py index c3a44f47b..bb8028eec 100644 --- a/netbox/extras/forms/customfields.py +++ b/netbox/extras/forms/customfields.py @@ -10,7 +10,12 @@ __all__ = ( class CustomFieldsMixin: """ Extend a Form to include custom field support. + + Attributes: + model: The model class """ + model = None + def __init__(self, *args, **kwargs): self.custom_fields = {} @@ -22,7 +27,7 @@ class CustomFieldsMixin: """ Return the ContentType of the form's model. """ - if not hasattr(self, 'model'): + if not getattr(self, 'model', None): raise NotImplementedError(f"{self.__class__.__name__} must specify a model class.") return ContentType.objects.get_for_model(self.model) diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py index 9a56501d2..6002c1fe4 100644 --- a/netbox/ipam/forms/bulk_edit.py +++ b/netbox/ipam/forms/bulk_edit.py @@ -49,6 +49,7 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = VRF nullable_fields = ('tenant', 'description') @@ -66,6 +67,7 @@ class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = RouteTarget nullable_fields = ('tenant', 'description') @@ -83,6 +85,7 @@ class RIRBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = RIR nullable_fields = ('is_private', 'description') @@ -109,6 +112,7 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ASN nullable_fields = ('date_added', 'description') @@ -134,6 +138,7 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Aggregate nullable_fields = ('date_added', 'description') @@ -150,6 +155,7 @@ class RoleBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Role nullable_fields = ('description',) @@ -212,6 +218,7 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Prefix nullable_fields = ( 'site', 'vrf', 'tenant', 'role', 'description', ) @@ -245,6 +252,7 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = IPRange nullable_fields = ( 'vrf', 'tenant', 'role', 'description', ) @@ -289,6 +297,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = IPAddress nullable_fields = ( 'vrf', 'role', 'tenant', 'dns_name', 'description', ) @@ -325,6 +334,7 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = FHRPGroup nullable_fields = ('auth_type', 'auth_key', 'description') @@ -354,6 +364,7 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = VLANGroup nullable_fields = ('site', 'description') @@ -403,6 +414,7 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = VLAN nullable_fields = ( 'site', 'group', 'tenant', 'role', 'description', ) @@ -430,6 +442,7 @@ class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ServiceTemplate nullable_fields = ('description',) diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 2de15c6b8..9cd6bbd47 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -5,7 +5,7 @@ from django.db.models import Q from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices from extras.forms.customfields import CustomFieldsMixin from extras.models import CustomField, Tag -from utilities.forms import BootstrapMixin, BulkEditMixin, CSVModelForm +from utilities.forms import BootstrapMixin, CSVModelForm from utilities.forms.fields import DynamicModelMultipleChoiceField __all__ = ( @@ -61,7 +61,7 @@ class NetBoxModelCSVForm(CSVModelForm, NetBoxModelForm): return customfield.to_form_field(for_csv_import=True) -class NetBoxModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditMixin, forms.Form): +class NetBoxModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, forms.Form): """ 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. @@ -69,6 +69,8 @@ class NetBoxModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditMixin, Attributes: nullable_fields: A list of field names indicating which fields support being set to null/empty """ + nullable_fields = () + add_tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), required=False diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index a042a3cff..3db44ec91 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -529,7 +529,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): initial_data['virtual_machine'] = request.GET.get('virtual_machine') if '_apply' in request.POST: - form = self.form(model, request.POST, initial=initial_data) + form = self.form(request.POST, initial=initial_data) restrict_form_fields(form, request.user) if form.is_valid(): @@ -566,7 +566,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): logger.debug("Form validation failed") else: - form = self.form(model, initial=initial_data) + form = self.form(initial=initial_data) restrict_form_fields(form, request.user) # Retrieve objects being edited diff --git a/netbox/tenancy/forms/bulk_edit.py b/netbox/tenancy/forms/bulk_edit.py index a3695c10e..c6d0be882 100644 --- a/netbox/tenancy/forms/bulk_edit.py +++ b/netbox/tenancy/forms/bulk_edit.py @@ -31,6 +31,7 @@ class TenantGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = TenantGroup nullable_fields = ('parent', 'description') @@ -44,6 +45,7 @@ class TenantBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Tenant nullable_fields = ('group',) @@ -65,6 +67,7 @@ class ContactGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ContactGroup nullable_fields = ('parent', 'description') @@ -78,6 +81,7 @@ class ContactRoleBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ContactRole nullable_fields = ('description',) @@ -106,4 +110,5 @@ class ContactBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = Contact nullable_fields = ('group', 'title', 'phone', 'email', 'address', 'comments') diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py index 67a2bcb74..05138df70 100644 --- a/netbox/utilities/forms/forms.py +++ b/netbox/utilities/forms/forms.py @@ -10,7 +10,6 @@ from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSel __all__ = ( 'BootstrapMixin', 'BulkEditForm', - 'BulkEditMixin', 'BulkRenameForm', 'ConfirmationForm', 'CSVModelForm', @@ -65,17 +64,6 @@ class BootstrapMixin: field.widget.attrs['class'] = ' '.join((css, 'form-select')).strip() -class BulkEditMixin: - """ - Base form for editing multiple objects in bulk - """ - nullable_fields = () - - def __init__(self, model, *args, **kwargs): - super().__init__(*args, **kwargs) - self.model = model - - # # Form classes # @@ -94,8 +82,11 @@ class ConfirmationForm(BootstrapMixin, ReturnURLForm): confirm = forms.BooleanField(required=True, widget=forms.HiddenInput(), initial=True) -class BulkEditForm(BootstrapMixin, BulkEditMixin, forms.Form): - pass +class BulkEditForm(BootstrapMixin, forms.Form): + """ + Provides bulk edit support for objects. + """ + nullable_fields = () class BulkRenameForm(BootstrapMixin, forms.Form): diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index e4f6ab25c..b3bf8adf8 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -33,6 +33,7 @@ class ClusterTypeBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ClusterType nullable_fields = ('description',) @@ -46,6 +47,7 @@ class ClusterGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = ClusterGroup nullable_fields = ('description',) @@ -87,6 +89,7 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = Cluster nullable_fields = ( 'group', 'site', 'comments', 'tenant', ) @@ -141,6 +144,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): label='Comments' ) + model = VirtualMachine nullable_fields = ( 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments', ) @@ -193,6 +197,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = VMInterface nullable_fields = ( 'parent', 'bridge', 'mtu', 'description', ) diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py index 0a3f0364e..91c34e4b1 100644 --- a/netbox/wireless/forms/bulk_edit.py +++ b/netbox/wireless/forms/bulk_edit.py @@ -29,6 +29,7 @@ class WirelessLANGroupBulkEditForm(NetBoxModelBulkEditForm): required=False ) + model = WirelessLANGroup nullable_fields = ('parent', 'description') @@ -67,6 +68,7 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): label='Pre-shared key' ) + model = WirelessLAN nullable_fields = ( 'ssid', 'group', 'vlan', 'description', 'auth_type', 'auth_cipher', 'auth_psk', ) @@ -102,6 +104,7 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): label='Pre-shared key' ) + model = WirelessLink nullable_fields = ( 'ssid', 'description', 'auth_type', 'auth_cipher', 'auth_psk', )