diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 89ec0383115..eead0751f4d 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -83,6 +83,7 @@ class ProviderBulkEditView(generic.BulkEditView): @register_model_view(Provider, 'bulk_rename', path='rename', detail=False) class ProviderBulkRenameView(generic.BulkRenameView): queryset = Provider.objects.all() + filterset = filtersets.ProviderFilterSet @register_model_view(Provider, 'bulk_delete', path='delete', detail=False) @@ -150,6 +151,7 @@ class ProviderAccountBulkEditView(generic.BulkEditView): @register_model_view(ProviderAccount, 'bulk_rename', path='rename', detail=False) class ProviderAccountBulkRenameView(generic.BulkRenameView): queryset = ProviderAccount.objects.all() + filterset = filtersets.ProviderAccountFilterSet @register_model_view(ProviderAccount, 'bulk_delete', path='delete', detail=False) @@ -226,6 +228,7 @@ class ProviderNetworkBulkEditView(generic.BulkEditView): @register_model_view(ProviderNetwork, 'bulk_rename', path='rename', detail=False) class ProviderNetworkBulkRenameView(generic.BulkRenameView): queryset = ProviderNetwork.objects.all() + filterset = filtersets.ProviderNetworkFilterSet @register_model_view(ProviderNetwork, 'bulk_delete', path='delete', detail=False) @@ -290,6 +293,7 @@ class CircuitTypeBulkEditView(generic.BulkEditView): @register_model_view(CircuitType, 'bulk_rename', path='rename', detail=False) class CircuitTypeBulkRenameView(generic.BulkRenameView): queryset = CircuitType.objects.all() + filterset = filtersets.CircuitTypeFilterSet @register_model_view(CircuitType, 'bulk_delete', path='delete', detail=False) @@ -362,6 +366,7 @@ class CircuitBulkEditView(generic.BulkEditView): class CircuitBulkRenameView(generic.BulkRenameView): queryset = Circuit.objects.all() field_name = 'cid' + filterset = filtersets.CircuitFilterSet @register_model_view(Circuit, 'bulk_delete', path='delete', detail=False) @@ -557,6 +562,7 @@ class CircuitGroupBulkEditView(generic.BulkEditView): @register_model_view(CircuitGroup, 'bulk_rename', path='rename', detail=False) class CircuitGroupBulkRenameView(generic.BulkRenameView): queryset = CircuitGroup.objects.all() + filterset = filtersets.CircuitGroupFilterSet @register_model_view(CircuitGroup, 'bulk_delete', path='delete', detail=False) @@ -672,6 +678,7 @@ class VirtualCircuitTypeBulkEditView(generic.BulkEditView): @register_model_view(VirtualCircuitType, 'bulk_rename', path='rename', detail=False) class VirtualCircuitTypeBulkRenameView(generic.BulkRenameView): queryset = VirtualCircuitType.objects.all() + filterset = filtersets.VirtualCircuitTypeFilterSet @register_model_view(VirtualCircuitType, 'bulk_delete', path='delete', detail=False) @@ -744,6 +751,7 @@ class VirtualCircuitBulkEditView(generic.BulkEditView): class VirtualCircuitBulkRenameView(generic.BulkRenameView): queryset = VirtualCircuit.objects.all() field_name = 'cid' + filterset = filtersets.VirtualCircuitFilterSet @register_model_view(VirtualCircuit, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/core/views.py b/netbox/core/views.py index 0959e1c12a0..b96392a9b69 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -125,6 +125,7 @@ class DataSourceBulkEditView(generic.BulkEditView): @register_model_view(DataSource, 'bulk_rename', path='rename', detail=False) class DataSourceBulkRenameView(generic.BulkRenameView): queryset = DataSource.objects.all() + filterset = filtersets.DataSourceFilterSet @register_model_view(DataSource, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 91453b44639..e1ba63ded67 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -2885,6 +2885,43 @@ def test_bulk_delete_child_interfaces(self): self.client.post(self._get_url('bulk_delete'), data) self.assertEqual(device.interfaces.count(), 4) # Child & parent were both deleted + def test_rename_select_all_spans_pages(self): + """ + Tests the bulk rename functionality for interfaces spanning multiple pages in the UI. + """ + device_name = 'DeviceRename' + device = create_test_device(device_name) + # Create > default page size (25) so selection spans multiple pages + for i in range(37): + Interface.objects.create(device=device, name=f'eth{i}') + + self.add_permissions('dcim.change_interface') + + # Filter to this device's interfaces to simulate a real list filter + get_qs = {'device_id': Device.objects.get(name=device_name).pk} + post_url = f'{self._get_url("bulk_rename")}?device_id={get_qs["device_id"]}' + + # Preview step: ensure 37 selected (not just one page) + data = {'_preview': '1', '_all': '1', 'find': 'eth', 'replace': 'xe'} + response = self.client.post(post_url, data=data) + self.assertHttpStatus(response, 200) + self.assertEqual(len(response.context['selected_objects']), 37) + + # Extract pk[] just like the browser would submit on Apply + # (either from the form's initial, or from selected_objects) + pk_list = response.context['form'].initial.get('pk') + if not pk_list: + pk_list = [obj.pk for obj in response.context['selected_objects']] + pk_list = [str(pk) for pk in pk_list] + + # Apply step: include pk[] in the POST + apply_data = {'_apply': '1', '_all': '1', 'find': 'eth', 'replace': 'xe', 'pk': pk_list} + response = self.client.post(post_url, data=apply_data) + + # On success the view redirects back to the return URL + self.assertHttpStatus(response, 302) + self.assertEqual(Interface.objects.filter(device=device, name__startswith='xe').count(), 37) + class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase): model = FrontPort diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 97ca998746f..a41078a112a 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -295,6 +295,7 @@ class RegionBulkEditView(generic.BulkEditView): @register_model_view(Region, 'bulk_rename', path='rename', detail=False) class RegionBulkRenameView(generic.BulkRenameView): queryset = Region.objects.all() + filterset = filtersets.RegionFilterSet @register_model_view(Region, 'bulk_delete', path='delete', detail=False) @@ -426,6 +427,7 @@ class SiteGroupBulkEditView(generic.BulkEditView): @register_model_view(SiteGroup, 'bulk_rename', path='rename', detail=False) class SiteGroupBulkRenameView(generic.BulkRenameView): queryset = SiteGroup.objects.all() + filterset = filtersets.SiteGroupFilterSet @register_model_view(SiteGroup, 'bulk_delete', path='delete', detail=False) @@ -516,6 +518,7 @@ class SiteBulkEditView(generic.BulkEditView): @register_model_view(Site, 'bulk_rename', path='rename', detail=False) class SiteBulkRenameView(generic.BulkRenameView): queryset = Site.objects.all() + filterset = filtersets.SiteFilterSet @register_model_view(Site, 'bulk_delete', path='delete', detail=False) @@ -625,6 +628,7 @@ class LocationBulkEditView(generic.BulkEditView): @register_model_view(Location, 'bulk_rename', path='rename', detail=False) class LocationBulkRenameView(generic.BulkRenameView): queryset = Location.objects.all() + filterset = filtersets.LocationFilterSet @register_model_view(Location, 'bulk_delete', path='delete', detail=False) @@ -695,6 +699,7 @@ class RackRoleBulkEditView(generic.BulkEditView): @register_model_view(RackRole, 'bulk_rename', path='rename', detail=False) class RackRoleBulkRenameView(generic.BulkRenameView): queryset = RackRole.objects.all() + filterset = filtersets.RackRoleFilterSet @register_model_view(RackRole, 'bulk_delete', path='delete', detail=False) @@ -760,6 +765,7 @@ class RackTypeBulkEditView(generic.BulkEditView): class RackTypeBulkRenameView(generic.BulkRenameView): queryset = RackType.objects.all() field_name = 'model' + filterset = filtersets.RackTypeFilterSet @register_model_view(RackType, 'bulk_delete', path='delete', detail=False) @@ -944,6 +950,7 @@ class RackBulkEditView(generic.BulkEditView): @register_model_view(Rack, 'bulk_rename', path='rename', detail=False) class RackBulkRenameView(generic.BulkRenameView): queryset = Rack.objects.all() + filterset = filtersets.RackFilterSet @register_model_view(Rack, 'bulk_delete', path='delete', detail=False) @@ -1083,6 +1090,7 @@ class ManufacturerBulkEditView(generic.BulkEditView): @register_model_view(Manufacturer, 'bulk_rename', path='rename', detail=False) class ManufacturerBulkRenameView(generic.BulkRenameView): queryset = Manufacturer.objects.all() + filterset = filtersets.ManufacturerFilterSet @register_model_view(Manufacturer, 'bulk_delete', path='delete', detail=False) @@ -1336,6 +1344,7 @@ class DeviceTypeBulkEditView(generic.BulkEditView): class DeviceTypeBulkRenameView(generic.BulkRenameView): queryset = DeviceType.objects.all() field_name = 'model' + filterset = filtersets.DeviceTypeFilterSet @register_model_view(DeviceType, 'bulk_delete', path='delete', detail=False) @@ -1397,6 +1406,7 @@ class ModuleTypeProfileBulkEditView(generic.BulkEditView): @register_model_view(ModuleTypeProfile, 'bulk_rename', path='rename', detail=False) class ModuleTypeProfileBulkRenameView(generic.BulkRenameView): queryset = ModuleTypeProfile.objects.all() + filterset = filtersets.ModuleTypeProfileFilterSet @register_model_view(ModuleTypeProfile, 'bulk_delete', path='delete', detail=False) @@ -1612,6 +1622,7 @@ class ModuleTypeBulkEditView(generic.BulkEditView): @register_model_view(ModuleType, 'bulk_rename', path='rename', detail=False) class ModuleTypeBulkRenameView(generic.BulkRenameView): queryset = ModuleType.objects.all() + filterset = filtersets.ModuleTypeFilterSet @register_model_view(ModuleType, 'bulk_delete', path='delete', detail=False) @@ -2100,6 +2111,7 @@ class DeviceRoleBulkEditView(generic.BulkEditView): @register_model_view(DeviceRole, 'bulk_rename', path='rename', detail=False) class DeviceRoleBulkRenameView(generic.BulkRenameView): queryset = DeviceRole.objects.all() + filterset = filtersets.DeviceRoleFilterSet @register_model_view(DeviceRole, 'bulk_delete', path='delete', detail=False) @@ -2175,6 +2187,7 @@ class PlatformBulkEditView(generic.BulkEditView): @register_model_view(Platform, 'bulk_rename', path='rename', detail=False) class PlatformBulkRenameView(generic.BulkRenameView): queryset = Platform.objects.all() + filterset = filtersets.PlatformFilterSet @register_model_view(Platform, 'bulk_delete', path='delete', detail=False) @@ -2582,6 +2595,7 @@ class ConsolePortBulkEditView(generic.BulkEditView): @register_model_view(ConsolePort, 'bulk_rename', path='rename', detail=False) class ConsolePortBulkRenameView(generic.BulkRenameView): queryset = ConsolePort.objects.all() + filterset = filtersets.ConsolePortFilterSet @register_model_view(ConsolePort, 'bulk_disconnect', path='disconnect', detail=False) @@ -2652,6 +2666,7 @@ class ConsoleServerPortBulkEditView(generic.BulkEditView): @register_model_view(ConsoleServerPort, 'bulk_rename', path='rename', detail=False) class ConsoleServerPortBulkRenameView(generic.BulkRenameView): queryset = ConsoleServerPort.objects.all() + filterset = filtersets.ConsoleServerPortFilterSet @register_model_view(ConsoleServerPort, 'bulk_disconnect', path='disconnect', detail=False) @@ -2722,6 +2737,7 @@ class PowerPortBulkEditView(generic.BulkEditView): @register_model_view(PowerPort, 'bulk_rename', path='rename', detail=False) class PowerPortBulkRenameView(generic.BulkRenameView): queryset = PowerPort.objects.all() + filterset = filtersets.PowerPortFilterSet @register_model_view(PowerPort, 'bulk_disconnect', path='disconnect', detail=False) @@ -2792,6 +2808,7 @@ class PowerOutletBulkEditView(generic.BulkEditView): @register_model_view(PowerOutlet, 'bulk_rename', path='rename', detail=False) class PowerOutletBulkRenameView(generic.BulkRenameView): queryset = PowerOutlet.objects.all() + filterset = filtersets.PowerOutletFilterSet @register_model_view(PowerOutlet, 'bulk_disconnect', path='disconnect', detail=False) @@ -2934,6 +2951,7 @@ def post_save_operations(self, form, obj): @register_model_view(Interface, 'bulk_rename', path='rename', detail=False) class InterfaceBulkRenameView(generic.BulkRenameView): queryset = Interface.objects.all() + filterset = filtersets.InterfaceFilterSet @register_model_view(Interface, 'bulk_disconnect', path='disconnect', detail=False) @@ -3005,6 +3023,7 @@ class FrontPortBulkEditView(generic.BulkEditView): @register_model_view(FrontPort, 'bulk_rename', path='rename', detail=False) class FrontPortBulkRenameView(generic.BulkRenameView): queryset = FrontPort.objects.all() + filterset = filtersets.FrontPortFilterSet @register_model_view(FrontPort, 'bulk_disconnect', path='disconnect', detail=False) @@ -3080,6 +3099,7 @@ class RearPortBulkRenameView(generic.BulkRenameView): @register_model_view(RearPort, 'bulk_disconnect', path='disconnect', detail=False) class RearPortBulkDisconnectView(BulkDisconnectView): queryset = RearPort.objects.all() + filterset = filtersets.RearPortFilterSet @register_model_view(RearPort, 'bulk_delete', path='delete', detail=False) @@ -3145,6 +3165,7 @@ class ModuleBayBulkEditView(generic.BulkEditView): @register_model_view(ModuleBay, 'bulk_rename', path='rename', detail=False) class ModuleBayBulkRenameView(generic.BulkRenameView): queryset = ModuleBay.objects.all() + filterset = filtersets.ModuleBayFilterSet @register_model_view(ModuleBay, 'bulk_delete', path='delete', detail=False) @@ -3287,6 +3308,7 @@ class DeviceBayBulkEditView(generic.BulkEditView): @register_model_view(DeviceBay, 'bulk_rename', path='rename', detail=False) class DeviceBayBulkRenameView(generic.BulkRenameView): queryset = DeviceBay.objects.all() + filterset = filtersets.DeviceBayFilterSet @register_model_view(DeviceBay, 'bulk_delete', path='delete', detail=False) @@ -3348,6 +3370,7 @@ class InventoryItemBulkEditView(generic.BulkEditView): @register_model_view(InventoryItem, 'bulk_rename', path='rename', detail=False) class InventoryItemBulkRenameView(generic.BulkRenameView): queryset = InventoryItem.objects.all() + filterset = filtersets.InventoryItemFilterSet @register_model_view(InventoryItem, 'bulk_delete', path='delete', detail=False) @@ -3431,6 +3454,7 @@ class InventoryItemRoleBulkEditView(generic.BulkEditView): @register_model_view(InventoryItemRole, 'bulk_rename', path='rename', detail=False) class InventoryItemRoleBulkRenameView(generic.BulkRenameView): queryset = InventoryItemRole.objects.all() + filterset = filtersets.InventoryItemRoleFilterSet @register_model_view(InventoryItemRole, 'bulk_delete', path='delete', detail=False) @@ -3634,6 +3658,7 @@ class CableBulkEditView(generic.BulkEditView): class CableBulkRenameView(generic.BulkRenameView): queryset = Cable.objects.all() field_name = 'label' + filterset = filtersets.CableFilterSet @register_model_view(Cable, 'bulk_delete', path='delete', detail=False) @@ -3931,6 +3956,7 @@ class VirtualChassisBulkEditView(generic.BulkEditView): @register_model_view(VirtualChassis, 'bulk_rename', path='rename', detail=False) class VirtualChassisBulkRenameView(generic.BulkRenameView): queryset = VirtualChassis.objects.all() + filterset = filtersets.VirtualChassisFilterSet @register_model_view(VirtualChassis, 'bulk_delete', path='delete', detail=False) @@ -3993,6 +4019,7 @@ class PowerPanelBulkEditView(generic.BulkEditView): @register_model_view(PowerPanel, 'bulk_rename', path='rename', detail=False) class PowerPanelBulkRenameView(generic.BulkRenameView): queryset = PowerPanel.objects.all() + filterset = filtersets.PowerPanelFilterSet @register_model_view(PowerPanel, 'bulk_delete', path='delete', detail=False) @@ -4050,6 +4077,7 @@ class PowerFeedBulkEditView(generic.BulkEditView): @register_model_view(PowerFeed, 'bulk_rename', path='rename', detail=False) class PowerFeedBulkRenameView(generic.BulkRenameView): queryset = PowerFeed.objects.all() + filterset = filtersets.PowerFeedFilterSet @register_model_view(PowerFeed, 'bulk_disconnect', path='disconnect', detail=False) @@ -4128,6 +4156,7 @@ class VirtualDeviceContextBulkEditView(generic.BulkEditView): @register_model_view(VirtualDeviceContext, 'bulk_rename', path='rename', detail=False) class VirtualDeviceContextBulkRenameView(generic.BulkRenameView): queryset = VirtualDeviceContext.objects.all() + filterset = filtersets.VirtualDeviceContextFilterSet @register_model_view(VirtualDeviceContext, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 32f87fb9708..50f77c8e3ac 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -101,6 +101,7 @@ class CustomFieldBulkEditView(generic.BulkEditView): @register_model_view(CustomField, 'bulk_rename', path='rename', detail=False) class CustomFieldBulkRenameView(generic.BulkRenameView): queryset = CustomField.objects.all() + filterset = filtersets.CustomFieldFilterSet @register_model_view(CustomField, 'bulk_delete', path='delete', detail=False) @@ -175,6 +176,7 @@ class CustomFieldChoiceSetBulkEditView(generic.BulkEditView): @register_model_view(CustomFieldChoiceSet, 'bulk_rename', path='rename', detail=False) class CustomFieldChoiceSetBulkRenameView(generic.BulkRenameView): queryset = CustomFieldChoiceSet.objects.all() + filterset = filtersets.CustomFieldChoiceSetFilterSet @register_model_view(CustomFieldChoiceSet, 'bulk_delete', path='delete', detail=False) @@ -230,6 +232,7 @@ class CustomLinkBulkEditView(generic.BulkEditView): @register_model_view(CustomLink, 'bulk_rename', path='rename', detail=False) class CustomLinkBulkRenameView(generic.BulkRenameView): queryset = CustomLink.objects.all() + filterset = filtersets.CustomLinkFilterSet @register_model_view(CustomLink, 'bulk_delete', path='delete', detail=False) @@ -286,6 +289,7 @@ class ExportTemplateBulkEditView(generic.BulkEditView): @register_model_view(ExportTemplate, 'bulk_rename', path='rename', detail=False) class ExportTemplateBulkRenameView(generic.BulkRenameView): queryset = ExportTemplate.objects.all() + filterset = filtersets.ExportTemplateFilterSet @register_model_view(ExportTemplate, 'bulk_delete', path='delete', detail=False) @@ -351,6 +355,7 @@ class SavedFilterBulkEditView(SharedObjectViewMixin, generic.BulkEditView): @register_model_view(SavedFilter, 'bulk_rename', path='rename', detail=False) class SavedFilterBulkRenameView(generic.BulkRenameView): queryset = SavedFilter.objects.all() + filterset = filtersets.SavedFilterFilterSet @register_model_view(SavedFilter, 'bulk_delete', path='delete', detail=False) @@ -413,6 +418,7 @@ class TableConfigBulkEditView(SharedObjectViewMixin, generic.BulkEditView): @register_model_view(TableConfig, 'bulk_rename', path='rename', detail=False) class TableConfigBulkRenameView(generic.BulkRenameView): queryset = TableConfig.objects.all() + filterset = filtersets.TableConfigFilterSet @register_model_view(TableConfig, 'bulk_delete', path='delete', detail=False) @@ -499,6 +505,7 @@ class NotificationGroupBulkEditView(generic.BulkEditView): @register_model_view(NotificationGroup, 'bulk_rename', path='rename', detail=False) class NotificationGroupBulkRenameView(generic.BulkRenameView): queryset = NotificationGroup.objects.all() + filterset = filtersets.NotificationGroupFilterSet @register_model_view(NotificationGroup, 'bulk_delete', path='delete', detail=False) @@ -650,6 +657,7 @@ class WebhookBulkEditView(generic.BulkEditView): @register_model_view(Webhook, 'bulk_rename', path='rename', detail=False) class WebhookBulkRenameView(generic.BulkRenameView): queryset = Webhook.objects.all() + filterset = filtersets.WebhookFilterSet @register_model_view(Webhook, 'bulk_delete', path='delete', detail=False) @@ -705,6 +713,7 @@ class EventRuleBulkEditView(generic.BulkEditView): @register_model_view(EventRule, 'bulk_rename', path='rename', detail=False) class EventRuleBulkRenameView(generic.BulkRenameView): queryset = EventRule.objects.all() + filterset = filtersets.EventRuleFilterSet @register_model_view(EventRule, 'bulk_delete', path='delete', detail=False) @@ -841,6 +850,7 @@ class ConfigContextProfileBulkEditView(generic.BulkEditView): @register_model_view(ConfigContextProfile, 'bulk_rename', path='rename', detail=False) class ConfigContextProfileBulkRenameView(generic.BulkRenameView): queryset = ConfigContextProfile.objects.all() + filterset = filtersets.ConfigContextProfileFilterSet @register_model_view(ConfigContextProfile, 'bulk_delete', path='delete', detail=False) @@ -929,6 +939,7 @@ class ConfigContextBulkEditView(generic.BulkEditView): @register_model_view(ConfigContext, 'bulk_rename', path='rename', detail=False) class ConfigContextBulkRenameView(generic.BulkRenameView): queryset = ConfigContext.objects.all() + filterset = filtersets.ConfigContextFilterSet @register_model_view(ConfigContext, 'bulk_delete', path='delete', detail=False) @@ -1020,6 +1031,7 @@ class ConfigTemplateBulkEditView(generic.BulkEditView): @register_model_view(ConfigTemplate, 'bulk_rename', path='rename', detail=False) class ConfigTemplateBulkRenameView(generic.BulkRenameView): queryset = ConfigTemplate.objects.all() + filterset = filtersets.ConfigTemplateFilterSet @register_model_view(ConfigTemplate, 'bulk_delete', path='delete', detail=False) @@ -1143,6 +1155,7 @@ class ImageAttachmentBulkEditView(generic.BulkEditView): @register_model_view(ImageAttachment, 'bulk_rename', path='rename', detail=False) class ImageAttachmentBulkRenameView(generic.BulkRenameView): queryset = ImageAttachment.objects.all() + filterset = filtersets.ImageAttachmentFilterSet @register_model_view(ImageAttachment, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 53e42c4fa0e..189f50a7a75 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -108,6 +108,7 @@ class VRFBulkEditView(generic.BulkEditView): @register_model_view(VRF, 'bulk_rename', path='rename', detail=False) class VRFBulkRenameView(generic.BulkRenameView): queryset = VRF.objects.all() + filterset = filtersets.VRFFilterSet @register_model_view(VRF, 'bulk_delete', path='delete', detail=False) @@ -163,6 +164,7 @@ class RouteTargetBulkEditView(generic.BulkEditView): @register_model_view(RouteTarget, 'bulk_rename', path='rename', detail=False) class RouteTargetBulkRenameView(generic.BulkRenameView): queryset = RouteTarget.objects.all() + filterset = filtersets.RouteTargetFilterSet @register_model_view(RouteTarget, 'bulk_delete', path='delete', detail=False) @@ -227,6 +229,7 @@ class RIRBulkEditView(generic.BulkEditView): @register_model_view(RIR, 'bulk_rename', path='rename', detail=False) class RIRBulkRenameView(generic.BulkRenameView): queryset = RIR.objects.all() + filterset = filtersets.RIRFilterSet @register_model_view(RIR, 'bulk_delete', path='delete', detail=False) @@ -305,6 +308,7 @@ class ASNRangeBulkEditView(generic.BulkEditView): @register_model_view(ASNRange, 'bulk_rename', path='rename', detail=False) class ASNRangeBulkRenameView(generic.BulkRenameView): queryset = ASNRange.objects.all() + filterset = filtersets.ASNRangeFilterSet @register_model_view(ASNRange, 'bulk_delete', path='delete', detail=False) @@ -377,6 +381,7 @@ class ASNBulkEditView(generic.BulkEditView): @register_model_view(ASN, 'bulk_rename', path='rename', detail=False) class ASNBulkRenameView(generic.BulkRenameView): queryset = ASN.objects.all() + filterset = filtersets.ASNFilterSet @register_model_view(ASN, 'bulk_delete', path='delete', detail=False) @@ -536,6 +541,7 @@ class RoleBulkEditView(generic.BulkEditView): @register_model_view(Role, 'bulk_rename', path='rename', detail=False) class RoleBulkRenameView(generic.BulkRenameView): queryset = Role.objects.all() + filterset = filtersets.RoleFilterSet @register_model_view(Role, 'bulk_delete', path='delete', detail=False) @@ -820,6 +826,7 @@ class IPRangeBulkEditView(generic.BulkEditView): @register_model_view(IPRange, 'bulk_rename', path='rename', detail=False) class IPRangeBulkRenameView(generic.BulkRenameView): queryset = IPRange.objects.all() + filterset = filtersets.IPRangeFilterSet @register_model_view(IPRange, 'bulk_delete', path='delete', detail=False) @@ -1066,6 +1073,7 @@ class VLANGroupBulkEditView(generic.BulkEditView): @register_model_view(VLANGroup, 'bulk_rename', path='rename', detail=False) class VLANGroupBulkRenameView(generic.BulkRenameView): queryset = VLANGroup.objects.all() + filterset = filtersets.VLANGroupFilterSet @register_model_view(VLANGroup, 'bulk_delete', path='delete', detail=False) @@ -1160,6 +1168,7 @@ class VLANTranslationPolicyBulkEditView(generic.BulkEditView): @register_model_view(VLANTranslationPolicy, 'bulk_rename', path='rename', detail=False) class VLANTranslationPolicyBulkRenameView(generic.BulkRenameView): queryset = VLANTranslationPolicy.objects.all() + filterset = filtersets.VLANTranslationPolicyFilterSet @register_model_view(VLANTranslationPolicy, 'bulk_delete', path='delete', detail=False) @@ -1315,6 +1324,7 @@ class FHRPGroupBulkEditView(generic.BulkEditView): @register_model_view(FHRPGroup, 'bulk_rename', path='rename', detail=False) class FHRPGroupBulkRenameView(generic.BulkRenameView): queryset = FHRPGroup.objects.all() + filterset = filtersets.FHRPGroupFilterSet @register_model_view(FHRPGroup, 'bulk_delete', path='delete', detail=False) @@ -1447,6 +1457,7 @@ class VLANBulkEditView(generic.BulkEditView): @register_model_view(VLAN, 'bulk_rename', path='rename', detail=False) class VLANBulkRenameView(generic.BulkRenameView): queryset = VLAN.objects.all() + filterset = filtersets.VLANFilterSet @register_model_view(VLAN, 'bulk_delete', path='delete', detail=False) @@ -1502,6 +1513,7 @@ class ServiceTemplateBulkEditView(generic.BulkEditView): @register_model_view(ServiceTemplate, 'bulk_rename', path='rename', detail=False) class ServiceTemplateBulkRenameView(generic.BulkRenameView): queryset = ServiceTemplate.objects.all() + filterset = filtersets.ServiceTemplateFilterSet @register_model_view(ServiceTemplate, 'bulk_delete', path='delete', detail=False) @@ -1574,6 +1586,7 @@ class ServiceBulkEditView(generic.BulkEditView): @register_model_view(Service, 'bulk_rename', path='rename', detail=False) class ServiceBulkRenameView(generic.BulkRenameView): queryset = Service.objects.all() + filterset = filtersets.ServiceFilterSet @register_model_view(Service, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index d9b2b875fa3..36c8ce1c45d 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -799,6 +799,9 @@ class BulkRenameView(GetReturnURLMixin, BaseMultiObjectView): """ field_name = 'name' template_name = 'generic/bulk_rename.html' + # Match BulkEditView/BulkDeleteView behavior: allow passing a FilterSet + # so "Select all N matching query" can expand across the full queryset. + filterset = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -840,9 +843,16 @@ def _rename_objects(self, form, selected_objects): def post(self, request): logger = logging.getLogger('netbox.views.BulkRenameView') + # If we are editing *all* objects in the queryset, replace the PK list with all matched objects. + if request.POST.get('_all') and self.filterset is not None: + pk_list = self.filterset(request.GET, self.queryset.values_list('pk', flat=True), request=request).qs + else: + pk_list = request.POST.getlist('pk') + + selected_objects = self.queryset.filter(pk__in=pk_list) + if '_preview' in request.POST or '_apply' in request.POST: - form = self.form(request.POST, initial={'pk': request.POST.getlist('pk')}) - selected_objects = self.queryset.filter(pk__in=form.initial['pk']) + form = self.form(request.POST, initial={'pk': pk_list}) if form.is_valid(): try: @@ -877,8 +887,7 @@ def post(self, request): clear_events.send(sender=self) else: - form = self.form(initial={'pk': request.POST.getlist('pk')}) - selected_objects = self.queryset.filter(pk__in=form.initial['pk']) + form = self.form(initial={'pk': pk_list}) return render(request, self.template_name, { 'field_name': self.field_name, diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 246f0a20072..57696d81612 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -74,6 +74,7 @@ class TenantGroupBulkEditView(generic.BulkEditView): @register_model_view(TenantGroup, 'bulk_rename', path='rename', detail=False) class TenantGroupBulkRenameView(generic.BulkRenameView): queryset = TenantGroup.objects.all() + filterset = filtersets.TenantGroupFilterSet @register_model_view(TenantGroup, 'bulk_delete', path='delete', detail=False) @@ -140,6 +141,7 @@ class TenantBulkEditView(generic.BulkEditView): @register_model_view(Tenant, 'bulk_rename', path='rename', detail=False) class TenantBulkRenameView(generic.BulkRenameView): queryset = Tenant.objects.all() + filterset = filtersets.TenantFilterSet @register_model_view(Tenant, 'bulk_delete', path='delete', detail=False) @@ -220,6 +222,7 @@ class ContactGroupBulkEditView(generic.BulkEditView): @register_model_view(ContactGroup, 'bulk_rename', path='rename', detail=False) class ContactGroupBulkRenameView(generic.BulkRenameView): queryset = ContactGroup.objects.all() + filterset = filtersets.ContactGroupFilterSet @register_model_view(ContactGroup, 'bulk_delete', path='delete', detail=False) @@ -286,6 +289,7 @@ class ContactRoleBulkEditView(generic.BulkEditView): @register_model_view(ContactRole, 'bulk_rename', path='rename', detail=False) class ContactRoleBulkRenameView(generic.BulkRenameView): queryset = ContactRole.objects.all() + filterset = filtersets.ContactRoleFilterSet @register_model_view(ContactRole, 'bulk_delete', path='delete', detail=False) @@ -354,6 +358,7 @@ def post_save_operations(self, form, obj): @register_model_view(Contact, 'bulk_rename', path='rename', detail=False) class ContactBulkRenameView(generic.BulkRenameView): queryset = Contact.objects.all() + filterset = filtersets.ContactFilterSet @register_model_view(Contact, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/users/views.py b/netbox/users/views.py index 9071c6c8bfa..c86aa485fe6 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -117,6 +117,7 @@ class UserBulkEditView(generic.BulkEditView): class UserBulkRenameView(generic.BulkRenameView): queryset = User.objects.all() field_name = 'username' + filterset = filtersets.UserFilterSet @register_model_view(User, 'bulk_delete', path='delete', detail=False) @@ -173,6 +174,7 @@ class GroupBulkEditView(generic.BulkEditView): @register_model_view(Group, 'bulk_rename', path='rename', detail=False) class GroupBulkRenameView(generic.BulkRenameView): queryset = Group.objects.all() + filterset = filtersets.GroupFilterSet @register_model_view(Group, 'bulk_delete', path='delete', detail=False) @@ -211,6 +213,7 @@ class ObjectPermissionEditView(generic.ObjectEditView): @register_model_view(ObjectPermission, 'delete') class ObjectPermissionDeleteView(generic.ObjectDeleteView): queryset = ObjectPermission.objects.all() + filterset = filtersets.ObjectPermissionFilterSet @register_model_view(ObjectPermission, 'bulk_edit', path='edit', detail=False) diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 358ab24141d..a7aa80f102e 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -80,6 +80,7 @@ class ClusterTypeBulkEditView(generic.BulkEditView): @register_model_view(ClusterType, 'bulk_rename', path='rename', detail=False) class ClusterTypeBulkRenameView(generic.BulkRenameView): queryset = ClusterType.objects.all() + filterset = filtersets.ClusterTypeFilterSet @register_model_view(ClusterType, 'bulk_delete', path='delete', detail=False) @@ -158,6 +159,7 @@ class ClusterGroupBulkEditView(generic.BulkEditView): @register_model_view(ClusterGroup, 'bulk_rename', path='rename', detail=False) class ClusterGroupBulkRenameView(generic.BulkRenameView): queryset = ClusterGroup.objects.all() + filterset = filtersets.ClusterGroupFilterSet @register_model_view(ClusterGroup, 'bulk_delete', path='delete', detail=False) @@ -277,6 +279,7 @@ class ClusterBulkEditView(generic.BulkEditView): @register_model_view(Cluster, 'bulk_rename', path='rename', detail=False) class ClusterBulkRenameView(generic.BulkRenameView): queryset = Cluster.objects.all() + filterset = filtersets.ClusterFilterSet @register_model_view(Cluster, 'bulk_delete', path='delete', detail=False) @@ -437,6 +440,7 @@ class VirtualMachineBulkEditView(generic.BulkEditView): @register_model_view(VirtualMachine, 'bulk_rename', path='rename', detail=False) class VirtualMachineBulkRenameView(generic.BulkRenameView): queryset = VirtualMachine.objects.all() + filterset = filtersets.VirtualMachineFilterSet @register_model_view(VirtualMachine, 'bulk_delete', path='delete', detail=False) @@ -539,6 +543,7 @@ class VMInterfaceBulkEditView(generic.BulkEditView): @register_model_view(VMInterface, 'bulk_rename', path='rename', detail=False) class VMInterfaceBulkRenameView(generic.BulkRenameView): queryset = VMInterface.objects.all() + filterset = filtersets.VMInterfaceFilterSet form = forms.VMInterfaceBulkRenameForm @@ -602,6 +607,7 @@ class VirtualDiskBulkEditView(generic.BulkEditView): @register_model_view(VirtualDisk, 'bulk_rename', path='rename', detail=False) class VirtualDiskBulkRenameView(generic.BulkRenameView): queryset = VirtualDisk.objects.all() + filterset = filtersets.VirtualDiskFilterSet form = forms.VirtualDiskBulkRenameForm diff --git a/netbox/vpn/views.py b/netbox/vpn/views.py index af9bf1b3433..1d699ab74d7 100644 --- a/netbox/vpn/views.py +++ b/netbox/vpn/views.py @@ -62,6 +62,7 @@ class TunnelGroupBulkEditView(generic.BulkEditView): @register_model_view(TunnelGroup, 'bulk_rename', path='rename', detail=False) class TunnelGroupBulkRenameView(generic.BulkRenameView): queryset = TunnelGroup.objects.all() + filterset = filtersets.TunnelGroupFilterSet @register_model_view(TunnelGroup, 'bulk_delete', path='delete', detail=False) @@ -131,6 +132,7 @@ class TunnelBulkEditView(generic.BulkEditView): @register_model_view(Tunnel, 'bulk_rename', path='rename', detail=False) class TunnelBulkRenameView(generic.BulkRenameView): queryset = Tunnel.objects.all() + filterset = filtersets.TunnelFilterSet @register_model_view(Tunnel, 'bulk_delete', path='delete', detail=False) @@ -238,6 +240,7 @@ class IKEProposalBulkEditView(generic.BulkEditView): @register_model_view(IKEProposal, 'bulk_rename', path='rename', detail=False) class IKEProposalBulkRenameView(generic.BulkRenameView): queryset = IKEProposal.objects.all() + filterset = filtersets.IKEProposalFilterSet @register_model_view(IKEProposal, 'bulk_delete', path='delete', detail=False) @@ -293,6 +296,7 @@ class IKEPolicyBulkEditView(generic.BulkEditView): @register_model_view(IKEPolicy, 'bulk_rename', path='rename', detail=False) class IKEPolicyBulkRenameView(generic.BulkRenameView): queryset = IKEPolicy.objects.all() + filterset = filtersets.IKEPolicyFilterSet @register_model_view(IKEPolicy, 'bulk_delete', path='delete', detail=False) @@ -348,6 +352,7 @@ class IPSecProposalBulkEditView(generic.BulkEditView): @register_model_view(IPSecProposal, 'bulk_rename', path='rename', detail=False) class IPSecProposalBulkRenameView(generic.BulkRenameView): queryset = IPSecProposal.objects.all() + filterset = filtersets.IPSecProposalFilterSet @register_model_view(IPSecProposal, 'bulk_delete', path='delete', detail=False) @@ -403,6 +408,7 @@ class IPSecPolicyBulkEditView(generic.BulkEditView): @register_model_view(IPSecPolicy, 'bulk_rename', path='rename', detail=False) class IPSecPolicyBulkRenameView(generic.BulkRenameView): queryset = IPSecPolicy.objects.all() + filterset = filtersets.IPSecPolicyFilterSet @register_model_view(IPSecPolicy, 'bulk_delete', path='delete', detail=False) @@ -458,6 +464,7 @@ class IPSecProfileBulkEditView(generic.BulkEditView): @register_model_view(IPSecProfile, 'bulk_rename', path='rename', detail=False) class IPSecProfileBulkRenameView(generic.BulkRenameView): queryset = IPSecProfile.objects.all() + filterset = filtersets.IPSecProfileFilterSet @register_model_view(IPSecProfile, 'bulk_delete', path='delete', detail=False) @@ -530,6 +537,7 @@ class L2VPNBulkEditView(generic.BulkEditView): @register_model_view(L2VPN, 'bulk_rename', path='rename', detail=False) class L2VPNBulkRenameView(generic.BulkRenameView): queryset = L2VPN.objects.all() + filterset = filtersets.L2VPNFilterSet @register_model_view(L2VPN, 'bulk_delete', path='delete', detail=False) diff --git a/netbox/wireless/views.py b/netbox/wireless/views.py index cc8f9d995cb..1f7c3fc7673 100644 --- a/netbox/wireless/views.py +++ b/netbox/wireless/views.py @@ -71,6 +71,7 @@ class WirelessLANGroupBulkEditView(generic.BulkEditView): @register_model_view(WirelessLANGroup, 'bulk_rename', path='rename', detail=False) class WirelessLANGroupBulkRenameView(generic.BulkRenameView): queryset = WirelessLANGroup.objects.all() + filterset = filtersets.WirelessLANGroupFilterSet @register_model_view(WirelessLANGroup, 'bulk_delete', path='delete', detail=False) @@ -146,6 +147,7 @@ class WirelessLANBulkEditView(generic.BulkEditView): class WirelessLANBulkRenameView(generic.BulkRenameView): queryset = WirelessLAN.objects.all() field_name = 'ssid' + filterset = filtersets.WirelessLANFilterSet @register_model_view(WirelessLAN, 'bulk_delete', path='delete', detail=False) @@ -202,6 +204,7 @@ class WirelessLinkBulkEditView(generic.BulkEditView): class WirelessLinkBulkRenameView(generic.BulkRenameView): queryset = WirelessLink.objects.all() field_name = 'ssid' + filterset = filtersets.WirelessLinkFilterSet @register_model_view(WirelessLink, 'bulk_delete', path='delete', detail=False)