Browse Source

#9623: Add slug field to SavedFilter

jeremystretch 3 years ago
parent
commit
355678274d

+ 3 - 3
netbox/circuits/forms/filtersets.py

@@ -20,7 +20,7 @@ __all__ = (
 class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Provider
     model = Provider
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('ASN', ('asn',)),
         ('ASN', ('asn',)),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
@@ -59,7 +59,7 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
 class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
     model = ProviderNetwork
     model = ProviderNetwork
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('provider_id', 'service_id')),
         ('Attributes', ('provider_id', 'service_id')),
     )
     )
     provider_id = DynamicModelMultipleChoiceField(
     provider_id = DynamicModelMultipleChoiceField(
@@ -82,7 +82,7 @@ class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Circuit
     model = Circuit
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Provider', ('provider_id', 'provider_network_id')),
         ('Provider', ('provider_id', 'provider_network_id')),
         ('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
         ('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),

+ 26 - 26
netbox/dcim/forms/filtersets.py

@@ -117,7 +117,7 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
 class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Region
     model = Region
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag', 'parent_id')),
+        (None, ('q', 'filter_id', 'tag', 'parent_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
@@ -131,7 +131,7 @@ class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = SiteGroup
     model = SiteGroup
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag', 'parent_id')),
+        (None, ('q', 'filter_id', 'tag', 'parent_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
@@ -145,7 +145,7 @@ class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Site
     model = Site
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('status', 'region_id', 'group_id', 'asn_id')),
         ('Attributes', ('status', 'region_id', 'group_id', 'asn_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
@@ -175,7 +175,7 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
 class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Location
     model = Location
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')),
         ('Attributes', ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
@@ -223,7 +223,7 @@ class RackRoleFilterForm(NetBoxModelFilterSetForm):
 class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Rack
     model = Rack
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Function', ('status', 'role_id')),
         ('Function', ('status', 'role_id')),
         ('Hardware', ('type', 'width', 'serial', 'asset_tag')),
         ('Hardware', ('type', 'width', 'serial', 'asset_tag')),
@@ -307,7 +307,7 @@ class RackElevationFilterForm(RackFilterForm):
 class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = RackReservation
     model = RackReservation
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('User', ('user_id',)),
         ('User', ('user_id',)),
         ('Rack', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
         ('Rack', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
@@ -363,7 +363,7 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Manufacturer
     model = Manufacturer
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
@@ -372,7 +372,7 @@ class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
 class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
     model = DeviceType
     model = DeviceType
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
         ('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
         ('Images', ('has_front_image', 'has_rear_image')),
         ('Images', ('has_front_image', 'has_rear_image')),
         ('Components', (
         ('Components', (
@@ -487,7 +487,7 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
 class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
 class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
     model = ModuleType
     model = ModuleType
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Hardware', ('manufacturer_id', 'part_number')),
         ('Hardware', ('manufacturer_id', 'part_number')),
         ('Components', (
         ('Components', (
             'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
             'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
@@ -579,7 +579,7 @@ class DeviceFilterForm(
 ):
 ):
     model = Device
     model = Device
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
         ('Operation', ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')),
         ('Operation', ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')),
         ('Hardware', ('manufacturer_id', 'device_type_id', 'platform_id')),
         ('Hardware', ('manufacturer_id', 'device_type_id', 'platform_id')),
@@ -735,7 +735,7 @@ class VirtualDeviceContextFilterForm(
 ):
 ):
     model = VirtualDeviceContext
     model = VirtualDeviceContext
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Hardware', ('device', 'status', )),
         ('Hardware', ('device', 'status', )),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Miscellaneous', ('has_primary_ip',))
         ('Miscellaneous', ('has_primary_ip',))
@@ -763,7 +763,7 @@ class VirtualDeviceContextFilterForm(
 class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
 class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Module
     model = Module
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Hardware', ('manufacturer_id', 'module_type_id', 'serial', 'asset_tag')),
         ('Hardware', ('manufacturer_id', 'module_type_id', 'serial', 'asset_tag')),
     )
     )
     manufacturer_id = DynamicModelMultipleChoiceField(
     manufacturer_id = DynamicModelMultipleChoiceField(
@@ -793,7 +793,7 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo
 class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VirtualChassis
     model = VirtualChassis
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -822,7 +822,7 @@ class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Cable
     model = Cable
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('site_id', 'location_id', 'rack_id', 'device_id')),
         ('Location', ('site_id', 'location_id', 'rack_id', 'device_id')),
         ('Attributes', ('type', 'status', 'color', 'length', 'length_unit')),
         ('Attributes', ('type', 'status', 'color', 'length', 'length_unit')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
@@ -894,7 +894,7 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = PowerPanel
     model = PowerPanel
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
     )
     )
@@ -932,7 +932,7 @@ class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class PowerFeedFilterForm(NetBoxModelFilterSetForm):
 class PowerFeedFilterForm(NetBoxModelFilterSetForm):
     model = PowerFeed
     model = PowerFeed
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')),
         ('Attributes', ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')),
         ('Attributes', ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')),
     )
     )
@@ -1034,7 +1034,7 @@ class PathEndpointFilterForm(CabledFilterForm):
 class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = ConsolePort
     model = ConsolePort
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type', 'speed')),
         ('Attributes', ('name', 'label', 'type', 'speed')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Connection', ('cabled', 'connected', 'occupied')),
         ('Connection', ('cabled', 'connected', 'occupied')),
@@ -1053,7 +1053,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = ConsoleServerPort
     model = ConsoleServerPort
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type', 'speed')),
         ('Attributes', ('name', 'label', 'type', 'speed')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Connection', ('cabled', 'connected', 'occupied')),
         ('Connection', ('cabled', 'connected', 'occupied')),
@@ -1072,7 +1072,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
 class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = PowerPort
     model = PowerPort
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type')),
         ('Attributes', ('name', 'label', 'type')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Connection', ('cabled', 'connected', 'occupied')),
         ('Connection', ('cabled', 'connected', 'occupied')),
@@ -1087,7 +1087,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = PowerOutlet
     model = PowerOutlet
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type')),
         ('Attributes', ('name', 'label', 'type')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Connection', ('cabled', 'connected', 'occupied')),
         ('Connection', ('cabled', 'connected', 'occupied')),
@@ -1102,7 +1102,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = Interface
     model = Interface
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')),
         ('Attributes', ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')),
         ('Addressing', ('vrf_id', 'mac_address', 'wwn')),
         ('Addressing', ('vrf_id', 'mac_address', 'wwn')),
         ('PoE', ('poe_mode', 'poe_type')),
         ('PoE', ('poe_mode', 'poe_type')),
@@ -1200,7 +1200,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 
 
 class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type', 'color')),
         ('Attributes', ('name', 'label', 'type', 'color')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Cable', ('cabled', 'occupied')),
         ('Cable', ('cabled', 'occupied')),
@@ -1219,7 +1219,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
     model = RearPort
     model = RearPort
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'type', 'color')),
         ('Attributes', ('name', 'label', 'type', 'color')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Cable', ('cabled', 'occupied')),
         ('Cable', ('cabled', 'occupied')),
@@ -1237,7 +1237,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class ModuleBayFilterForm(DeviceComponentFilterForm):
 class ModuleBayFilterForm(DeviceComponentFilterForm):
     model = ModuleBay
     model = ModuleBay
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'position')),
         ('Attributes', ('name', 'label', 'position')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
     )
     )
@@ -1250,7 +1250,7 @@ class ModuleBayFilterForm(DeviceComponentFilterForm):
 class DeviceBayFilterForm(DeviceComponentFilterForm):
 class DeviceBayFilterForm(DeviceComponentFilterForm):
     model = DeviceBay
     model = DeviceBay
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label')),
         ('Attributes', ('name', 'label')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
     )
     )
@@ -1260,7 +1260,7 @@ class DeviceBayFilterForm(DeviceComponentFilterForm):
 class InventoryItemFilterForm(DeviceComponentFilterForm):
 class InventoryItemFilterForm(DeviceComponentFilterForm):
     model = InventoryItem
     model = InventoryItem
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')),
         ('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
         ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
     )
     )

+ 1 - 1
netbox/extras/api/nested_serializers.py

@@ -64,7 +64,7 @@ class NestedSavedFilterSerializer(WritableNestedSerializer):
 
 
     class Meta:
     class Meta:
         model = models.SavedFilter
         model = models.SavedFilter
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display', 'name', 'slug']
 
 
 
 
 class NestedImageAttachmentSerializer(WritableNestedSerializer):
 class NestedImageAttachmentSerializer(WritableNestedSerializer):

+ 2 - 2
netbox/extras/api/serializers.py

@@ -164,8 +164,8 @@ class SavedFilterSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = SavedFilter
         model = SavedFilter
         fields = [
         fields = [
-            'id', 'url', 'display', 'content_types', 'name', 'description', 'user', 'weight',
-            'enabled', 'shared', 'parameters', 'created', 'last_updated',
+            'id', 'url', 'display', 'content_types', 'name', 'slug', 'description', 'user', 'weight', 'enabled',
+            'shared', 'parameters', 'created', 'last_updated',
         ]
         ]
 
 
 
 

+ 1 - 1
netbox/extras/filtersets.py

@@ -165,7 +165,7 @@ class SavedFilterFilterSet(BaseFilterSet):
 
 
     class Meta:
     class Meta:
         model = SavedFilter
         model = SavedFilter
-        fields = ['id', 'content_types', 'name', 'description', 'enabled', 'shared', 'weight']
+        fields = ['id', 'content_types', 'name', 'slug', 'description', 'enabled', 'shared', 'weight']
 
 
     def search(self, queryset, name, value):
     def search(self, queryset, name, value):
         if not value.strip():
         if not value.strip():

+ 1 - 1
netbox/extras/forms/bulk_import.py

@@ -92,7 +92,7 @@ class SavedFilterCSVForm(CSVModelForm):
     class Meta:
     class Meta:
         model = SavedFilter
         model = SavedFilter
         fields = (
         fields = (
-            'name', 'content_types', 'description', 'weight', 'enabled', 'shared', 'parameters',
+            'name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared', 'parameters',
         )
         )
 
 
 
 

+ 9 - 9
netbox/extras/forms/filtersets.py

@@ -34,7 +34,7 @@ __all__ = (
 
 
 class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
 class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('type', 'content_type_id', 'group_name', 'weight', 'required', 'ui_visibility')),
         ('Attributes', ('type', 'content_type_id', 'group_name', 'weight', 'required', 'ui_visibility')),
     )
     )
     content_type_id = ContentTypeMultipleChoiceField(
     content_type_id = ContentTypeMultipleChoiceField(
@@ -70,7 +70,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class JobResultFilterForm(SavedFiltersMixin, FilterForm):
 class JobResultFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('obj_type', 'status')),
         ('Attributes', ('obj_type', 'status')),
         ('Creation', ('created__before', 'created__after', 'completed__before', 'completed__after',
         ('Creation', ('created__before', 'created__after', 'completed__before', 'completed__after',
                       'scheduled_time__before', 'scheduled_time__after', 'user')),
                       'scheduled_time__before', 'scheduled_time__after', 'user')),
@@ -122,7 +122,7 @@ class JobResultFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
 class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('content_types', 'enabled', 'new_window', 'weight')),
         ('Attributes', ('content_types', 'enabled', 'new_window', 'weight')),
     )
     )
     content_types = ContentTypeMultipleChoiceField(
     content_types = ContentTypeMultipleChoiceField(
@@ -149,7 +149,7 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
 class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('content_types', 'mime_type', 'file_extension', 'as_attachment')),
         ('Attributes', ('content_types', 'mime_type', 'file_extension', 'as_attachment')),
     )
     )
     content_types = ContentTypeMultipleChoiceField(
     content_types = ContentTypeMultipleChoiceField(
@@ -174,7 +174,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
 class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('content_types', 'enabled', 'shared', 'weight')),
         ('Attributes', ('content_types', 'enabled', 'shared', 'weight')),
     )
     )
     content_types = ContentTypeMultipleChoiceField(
     content_types = ContentTypeMultipleChoiceField(
@@ -201,7 +201,7 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class WebhookFilterForm(SavedFiltersMixin, FilterForm):
 class WebhookFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Attributes', ('content_type_id', 'http_method', 'enabled')),
         ('Attributes', ('content_type_id', 'http_method', 'enabled')),
         ('Events', ('type_create', 'type_update', 'type_delete')),
         ('Events', ('type_create', 'type_update', 'type_delete')),
     )
     )
@@ -253,7 +253,7 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
 
 
 class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
 class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag_id')),
+        (None, ('q', 'filter_id', 'tag_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
         ('Device', ('device_type_id', 'platform_id', 'role_id')),
         ('Device', ('device_type_id', 'platform_id', 'role_id')),
         ('Cluster', ('cluster_type_id', 'cluster_group_id', 'cluster_id')),
         ('Cluster', ('cluster_type_id', 'cluster_group_id', 'cluster_id')),
@@ -340,7 +340,7 @@ class LocalConfigContextFilterForm(forms.Form):
 class JournalEntryFilterForm(NetBoxModelFilterSetForm):
 class JournalEntryFilterForm(NetBoxModelFilterSetForm):
     model = JournalEntry
     model = JournalEntry
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Creation', ('created_before', 'created_after', 'created_by_id')),
         ('Creation', ('created_before', 'created_after', 'created_by_id')),
         ('Attributes', ('assigned_object_type_id', 'kind'))
         ('Attributes', ('assigned_object_type_id', 'kind'))
     )
     )
@@ -381,7 +381,7 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm):
 class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm):
 class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm):
     model = ObjectChange
     model = ObjectChange
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter')),
+        (None, ('q', 'filter_id')),
         ('Time', ('time_before', 'time_after')),
         ('Time', ('time_before', 'time_after')),
         ('Attributes', ('action', 'user_id', 'changed_object_type_id')),
         ('Attributes', ('action', 'user_id', 'changed_object_type_id')),
     )
     )

+ 1 - 1
netbox/extras/forms/mixins.py

@@ -64,7 +64,7 @@ class CustomFieldsMixin:
 
 
 
 
 class SavedFiltersMixin(forms.Form):
 class SavedFiltersMixin(forms.Form):
-    filter = DynamicModelMultipleChoiceField(
+    filter_id = DynamicModelMultipleChoiceField(
         queryset=SavedFilter.objects.all(),
         queryset=SavedFilter.objects.all(),
         required=False,
         required=False,
         label=_('Saved Filter'),
         label=_('Saved Filter'),

+ 2 - 1
netbox/extras/forms/model_forms.py

@@ -112,12 +112,13 @@ class ExportTemplateForm(BootstrapMixin, forms.ModelForm):
 
 
 
 
 class SavedFilterForm(BootstrapMixin, forms.ModelForm):
 class SavedFilterForm(BootstrapMixin, forms.ModelForm):
+    slug = SlugField()
     content_types = ContentTypeMultipleChoiceField(
     content_types = ContentTypeMultipleChoiceField(
         queryset=ContentType.objects.all()
         queryset=ContentType.objects.all()
     )
     )
 
 
     fieldsets = (
     fieldsets = (
-        ('Saved Filter', ('name', 'content_types', 'description', 'weight', 'enabled', 'shared')),
+        ('Saved Filter', ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')),
         ('Parameters', ('parameters',)),
         ('Parameters', ('parameters',)),
     )
     )
 
 

+ 2 - 3
netbox/extras/migrations/0082_savedfilter.py

@@ -1,8 +1,6 @@
-# Generated by Django 4.1.1 on 2022-10-27 18:18
-
+import django.db.models.deletion
 from django.conf import settings
 from django.conf import settings
 from django.db import migrations, models
 from django.db import migrations, models
-import django.db.models.deletion
 
 
 
 
 class Migration(migrations.Migration):
 class Migration(migrations.Migration):
@@ -21,6 +19,7 @@ class Migration(migrations.Migration):
                 ('created', models.DateTimeField(auto_now_add=True, null=True)),
                 ('created', models.DateTimeField(auto_now_add=True, null=True)),
                 ('last_updated', models.DateTimeField(auto_now=True, null=True)),
                 ('last_updated', models.DateTimeField(auto_now=True, null=True)),
                 ('name', models.CharField(max_length=100, unique=True)),
                 ('name', models.CharField(max_length=100, unique=True)),
+                ('slug', models.SlugField(max_length=100, unique=True)),
                 ('description', models.CharField(blank=True, max_length=200)),
                 ('description', models.CharField(blank=True, max_length=200)),
                 ('weight', models.PositiveSmallIntegerField(default=100)),
                 ('weight', models.PositiveSmallIntegerField(default=100)),
                 ('enabled', models.BooleanField(default=True)),
                 ('enabled', models.BooleanField(default=True)),

+ 4 - 0
netbox/extras/models/models.py

@@ -365,6 +365,10 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
         max_length=100,
         max_length=100,
         unique=True
         unique=True
     )
     )
+    slug = models.SlugField(
+        max_length=100,
+        unique=True
+    )
     description = models.CharField(
     description = models.CharField(
         max_length=200,
         max_length=200,
         blank=True
         blank=True

+ 1 - 1
netbox/extras/tables/tables.py

@@ -100,7 +100,7 @@ class SavedFilterTable(NetBoxTable):
     class Meta(NetBoxTable.Meta):
     class Meta(NetBoxTable.Meta):
         model = SavedFilter
         model = SavedFilter
         fields = (
         fields = (
-            'pk', 'id', 'name', 'content_types', 'description', 'user', 'weight', 'enabled', 'shared',
+            'pk', 'id', 'name', 'slug', 'content_types', 'description', 'user', 'weight', 'enabled', 'shared',
             'created', 'last_updated',
             'created', 'last_updated',
         )
         )
         default_columns = (
         default_columns = (

+ 7 - 1
netbox/extras/tests/test_api.py

@@ -192,11 +192,12 @@ class CustomLinkTest(APIViewTestCases.APIViewTestCase):
 
 
 class SavedFilterTest(APIViewTestCases.APIViewTestCase):
 class SavedFilterTest(APIViewTestCases.APIViewTestCase):
     model = SavedFilter
     model = SavedFilter
-    brief_fields = ['display', 'id', 'name', 'url']
+    brief_fields = ['display', 'id', 'name', 'slug', 'url']
     create_data = [
     create_data = [
         {
         {
             'content_types': ['dcim.site'],
             'content_types': ['dcim.site'],
             'name': 'Saved Filter 4',
             'name': 'Saved Filter 4',
+            'slug': 'saved-filter-4',
             'weight': 100,
             'weight': 100,
             'enabled': True,
             'enabled': True,
             'shared': True,
             'shared': True,
@@ -205,6 +206,7 @@ class SavedFilterTest(APIViewTestCases.APIViewTestCase):
         {
         {
             'content_types': ['dcim.site'],
             'content_types': ['dcim.site'],
             'name': 'Saved Filter 5',
             'name': 'Saved Filter 5',
+            'slug': 'saved-filter-5',
             'weight': 200,
             'weight': 200,
             'enabled': True,
             'enabled': True,
             'shared': True,
             'shared': True,
@@ -213,6 +215,7 @@ class SavedFilterTest(APIViewTestCases.APIViewTestCase):
         {
         {
             'content_types': ['dcim.site'],
             'content_types': ['dcim.site'],
             'name': 'Saved Filter 6',
             'name': 'Saved Filter 6',
+            'slug': 'saved-filter-6',
             'weight': 300,
             'weight': 300,
             'enabled': True,
             'enabled': True,
             'shared': True,
             'shared': True,
@@ -232,6 +235,7 @@ class SavedFilterTest(APIViewTestCases.APIViewTestCase):
         saved_filters = (
         saved_filters = (
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 1',
                 name='Saved Filter 1',
+                slug='saved-filter-1',
                 weight=100,
                 weight=100,
                 enabled=True,
                 enabled=True,
                 shared=True,
                 shared=True,
@@ -239,6 +243,7 @@ class SavedFilterTest(APIViewTestCases.APIViewTestCase):
             ),
             ),
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 2',
                 name='Saved Filter 2',
+                slug='saved-filter-2',
                 weight=200,
                 weight=200,
                 enabled=True,
                 enabled=True,
                 shared=True,
                 shared=True,
@@ -246,6 +251,7 @@ class SavedFilterTest(APIViewTestCases.APIViewTestCase):
             ),
             ),
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 3',
                 name='Saved Filter 3',
+                slug='saved-filter-3',
                 weight=300,
                 weight=300,
                 enabled=True,
                 enabled=True,
                 shared=True,
                 shared=True,

+ 7 - 0
netbox/extras/tests/test_filtersets.py

@@ -240,6 +240,7 @@ class SavedFilterTestCase(TestCase, BaseFilterSetTests):
         saved_filters = (
         saved_filters = (
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 1',
                 name='Saved Filter 1',
+                slug='saved-filter-1',
                 user=users[0],
                 user=users[0],
                 weight=100,
                 weight=100,
                 enabled=True,
                 enabled=True,
@@ -248,6 +249,7 @@ class SavedFilterTestCase(TestCase, BaseFilterSetTests):
             ),
             ),
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 2',
                 name='Saved Filter 2',
+                slug='saved-filter-2',
                 user=users[1],
                 user=users[1],
                 weight=200,
                 weight=200,
                 enabled=True,
                 enabled=True,
@@ -256,6 +258,7 @@ class SavedFilterTestCase(TestCase, BaseFilterSetTests):
             ),
             ),
             SavedFilter(
             SavedFilter(
                 name='Saved Filter 3',
                 name='Saved Filter 3',
+                slug='saved-filter-3',
                 user=users[2],
                 user=users[2],
                 weight=300,
                 weight=300,
                 enabled=False,
                 enabled=False,
@@ -271,6 +274,10 @@ class SavedFilterTestCase(TestCase, BaseFilterSetTests):
         params = {'name': ['Saved Filter 1', 'Saved Filter 2']}
         params = {'name': ['Saved Filter 1', 'Saved Filter 2']}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 
 
+    def test_slug(self):
+        params = {'slug': ['saved-filter-1', 'saved-filter-2']}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
     def test_content_types(self):
     def test_content_types(self):
         params = {'content_types': 'dcim.site'}
         params = {'content_types': 'dcim.site'}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)

+ 26 - 7
netbox/extras/tests/test_views.py

@@ -122,9 +122,27 @@ class SavedFilterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         User.objects.bulk_create(users)
         User.objects.bulk_create(users)
 
 
         saved_filters = (
         saved_filters = (
-            SavedFilter(name='Saved Filter 1', user=users[0], weight=100, parameters={'status': ['active']}),
-            SavedFilter(name='Saved Filter 2', user=users[1], weight=200, parameters={'status': ['planned']}),
-            SavedFilter(name='Saved Filter 3', user=users[2], weight=300, parameters={'status': ['retired']}),
+            SavedFilter(
+                name='Saved Filter 1',
+                slug='saved-filter-1',
+                user=users[0],
+                weight=100,
+                parameters={'status': ['active']}
+            ),
+            SavedFilter(
+                name='Saved Filter 2',
+                slug='saved-filter-2',
+                user=users[1],
+                weight=200,
+                parameters={'status': ['planned']}
+            ),
+            SavedFilter(
+                name='Saved Filter 3',
+                slug='saved-filter-3',
+                user=users[2],
+                weight=300,
+                parameters={'status': ['retired']}
+            ),
         )
         )
         SavedFilter.objects.bulk_create(saved_filters)
         SavedFilter.objects.bulk_create(saved_filters)
         for i, savedfilter in enumerate(saved_filters):
         for i, savedfilter in enumerate(saved_filters):
@@ -132,6 +150,7 @@ class SavedFilterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
 
 
         cls.form_data = {
         cls.form_data = {
             'name': 'Saved Filter X',
             'name': 'Saved Filter X',
+            'slug': 'saved-filter-x',
             'content_types': [site_ct.pk],
             'content_types': [site_ct.pk],
             'description': 'Foo',
             'description': 'Foo',
             'weight': 1000,
             'weight': 1000,
@@ -141,10 +160,10 @@ class SavedFilterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
         }
         }
 
 
         cls.csv_data = (
         cls.csv_data = (
-            'name,content_types,weight,enabled,shared,parameters',
-            'Saved Filter 4,dcim.device,400,True,True,{"foo": "a"}',
-            'Saved Filter 5,dcim.device,500,True,True,{"foo": "b"}',
-            'Saved Filter 6,dcim.device,600,True,True,{"foo": "c"}',
+            'name,slug,content_types,weight,enabled,shared,parameters',
+            'Saved Filter 4,saved-filter-4,dcim.device,400,True,True,{"foo": "a"}',
+            'Saved Filter 5,saved-filter-5,dcim.device,500,True,True,{"foo": "b"}',
+            'Saved Filter 6,saved-filter-6,dcim.device,600,True,True,{"foo": "c"}',
         )
         )
 
 
         cls.csv_update_data = (
         cls.csv_update_data = (

+ 13 - 13
netbox/ipam/forms/filtersets.py

@@ -45,7 +45,7 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
 class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VRF
     model = VRF
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Route Targets', ('import_target_id', 'export_target_id')),
         ('Route Targets', ('import_target_id', 'export_target_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -65,7 +65,7 @@ class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = RouteTarget
     model = RouteTarget
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('VRF', ('importing_vrf_id', 'exporting_vrf_id')),
         ('VRF', ('importing_vrf_id', 'exporting_vrf_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -97,7 +97,7 @@ class RIRFilterForm(NetBoxModelFilterSetForm):
 class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Aggregate
     model = Aggregate
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('family', 'rir_id')),
         ('Attributes', ('family', 'rir_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -118,7 +118,7 @@ class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = ASN
     model = ASN
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Assignment', ('rir_id', 'site_id')),
         ('Assignment', ('rir_id', 'site_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -143,7 +143,7 @@ class RoleFilterForm(NetBoxModelFilterSetForm):
 class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Prefix
     model = Prefix
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Addressing', ('within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized')),
         ('Addressing', ('within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized')),
         ('VRF', ('vrf_id', 'present_in_vrf_id')),
         ('VRF', ('vrf_id', 'present_in_vrf_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
@@ -232,7 +232,7 @@ class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = IPRange
     model = IPRange
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attriubtes', ('family', 'vrf_id', 'status', 'role_id')),
         ('Attriubtes', ('family', 'vrf_id', 'status', 'role_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -264,7 +264,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = IPAddress
     model = IPAddress
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface')),
         ('Attributes', ('parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface')),
         ('VRF', ('vrf_id', 'present_in_vrf_id')),
         ('VRF', ('vrf_id', 'present_in_vrf_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
@@ -333,7 +333,7 @@ class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class FHRPGroupFilterForm(NetBoxModelFilterSetForm):
 class FHRPGroupFilterForm(NetBoxModelFilterSetForm):
     model = FHRPGroup
     model = FHRPGroup
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('name', 'protocol', 'group_id')),
         ('Attributes', ('name', 'protocol', 'group_id')),
         ('Authentication', ('auth_type', 'auth_key')),
         ('Authentication', ('auth_type', 'auth_key')),
     )
     )
@@ -363,7 +363,7 @@ class FHRPGroupFilterForm(NetBoxModelFilterSetForm):
 
 
 class VLANGroupFilterForm(NetBoxModelFilterSetForm):
 class VLANGroupFilterForm(NetBoxModelFilterSetForm):
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region', 'sitegroup', 'site', 'location', 'rack')),
         ('Location', ('region', 'sitegroup', 'site', 'location', 'rack')),
         ('VLAN ID', ('min_vid', 'max_vid')),
         ('VLAN ID', ('min_vid', 'max_vid')),
     )
     )
@@ -411,7 +411,7 @@ class VLANGroupFilterForm(NetBoxModelFilterSetForm):
 class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VLAN
     model = VLAN
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Attributes', ('group_id', 'status', 'role_id', 'vid')),
         ('Attributes', ('group_id', 'status', 'role_id', 'vid')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
@@ -464,7 +464,7 @@ class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class ServiceTemplateFilterForm(NetBoxModelFilterSetForm):
 class ServiceTemplateFilterForm(NetBoxModelFilterSetForm):
     model = ServiceTemplate
     model = ServiceTemplate
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('protocol', 'port')),
         ('Attributes', ('protocol', 'port')),
     )
     )
     protocol = forms.ChoiceField(
     protocol = forms.ChoiceField(
@@ -485,7 +485,7 @@ class ServiceFilterForm(ServiceTemplateFilterForm):
 class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = L2VPN
     model = L2VPN
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('type', 'import_target_id', 'export_target_id')),
         ('Attributes', ('type', 'import_target_id', 'export_target_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
     )
     )
@@ -510,7 +510,7 @@ class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
 class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm):
     model = L2VPNTermination
     model = L2VPNTermination
     fieldsets = (
     fieldsets = (
-        (None, ('filter', 'l2vpn_id',)),
+        (None, ('filter_id', 'l2vpn_id',)),
         ('Assigned Object', (
         ('Assigned Object', (
             'assigned_object_type_id', 'region_id', 'site_id', 'device_id', 'virtual_machine_id', 'vlan_id',
             'assigned_object_type_id', 'region_id', 'site_id', 'device_id', 'virtual_machine_id', 'vlan_id',
         )),
         )),

+ 6 - 3
netbox/netbox/filtersets.py

@@ -2,9 +2,9 @@ import django_filters
 from copy import deepcopy
 from copy import deepcopy
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db import models
+from django.db.models import Q
 from django_filters.exceptions import FieldLookupError
 from django_filters.exceptions import FieldLookupError
 from django_filters.utils import get_model_field, resolve_field
 from django_filters.utils import get_model_field, resolve_field
-from django.shortcuts import get_object_or_404
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
 from extras.choices import CustomFieldFilterLogicChoices
 from extras.choices import CustomFieldFilterLogicChoices
@@ -89,9 +89,12 @@ class BaseFilterSet(django_filters.FilterSet):
         self.base_filters = self.__class__.get_filters()
         self.base_filters = self.__class__.get_filters()
 
 
         # Apply any referenced SavedFilters
         # Apply any referenced SavedFilters
-        if data and 'filter' in data:
+        if data and ('filter' in data or 'filter_id' in data):
             data = data.copy()  # Get a mutable copy
             data = data.copy()  # Get a mutable copy
-            saved_filters = SavedFilter.objects.filter(pk__in=data.pop('filter'))
+            saved_filters = SavedFilter.objects.filter(
+                Q(slug__in=data.pop('filter', [])) |
+                Q(pk__in=data.pop('filter_id', []))
+            )
             for sf in saved_filters:
             for sf in saved_filters:
                 for key, value in sf.parameters.items():
                 for key, value in sf.parameters.items():
                     # QueryDicts are... fun
                     # QueryDicts are... fun

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

@@ -141,7 +141,7 @@ class NetBoxModelFilterSetForm(BootstrapMixin, CustomFieldsMixin, SavedFiltersMi
 
 
         # Limit saved filters to those applicable to the form's model
         # Limit saved filters to those applicable to the form's model
         content_type = ContentType.objects.get_for_model(self.model)
         content_type = ContentType.objects.get_for_model(self.model)
-        self.fields['filter'].widget.add_query_params({
+        self.fields['filter_id'].widget.add_query_params({
             'content_type_id': content_type.pk,
             'content_type_id': content_type.pk,
         })
         })
 
 

+ 1 - 1
netbox/tenancy/forms/filtersets.py

@@ -31,7 +31,7 @@ class TenantGroupFilterForm(NetBoxModelFilterSetForm):
 class TenantFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class TenantFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Tenant
     model = Tenant
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag', 'group_id')),
+        (None, ('q', 'filter_id', 'tag', 'group_id')),
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
         ('Contacts', ('contact', 'contact_role', 'contact_group'))
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(

+ 1 - 1
netbox/utilities/templatetags/helpers.py

@@ -309,7 +309,7 @@ def applied_filters(context, model, form, query_params):
         })
         })
 
 
     save_link = None
     save_link = None
-    if user.has_perm('extras.add_savedfilter') and 'filter' not in context['request'].GET:
+    if user.has_perm('extras.add_savedfilter') and 'filter_id' not in context['request'].GET:
         content_type = ContentType.objects.get_for_model(model).pk
         content_type = ContentType.objects.get_for_model(model).pk
         parameters = context['request'].GET.urlencode()
         parameters = context['request'].GET.urlencode()
         url = reverse('extras:savedfilter_add')
         url = reverse('extras:savedfilter_add')

+ 4 - 4
netbox/virtualization/forms/filtersets.py

@@ -30,7 +30,7 @@ class ClusterGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = ClusterGroup
     model = ClusterGroup
     tag = TagFilterField(model)
     tag = TagFilterField(model)
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
         ('Contacts', ('contact', 'contact_role', 'contact_group')),
     )
     )
 
 
@@ -38,7 +38,7 @@ class ClusterGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
 class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Cluster
     model = Cluster
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('group_id', 'type_id', 'status')),
         ('Attributes', ('group_id', 'type_id', 'status')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
@@ -90,7 +90,7 @@ class VirtualMachineFilterForm(
 ):
 ):
     model = VirtualMachine
     model = VirtualMachine
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Cluster', ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')),
         ('Cluster', ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Location', ('region_id', 'site_group_id', 'site_id')),
         ('Attributes', ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data')),
         ('Attributes', ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data')),
@@ -175,7 +175,7 @@ class VirtualMachineFilterForm(
 class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
 class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
     model = VMInterface
     model = VMInterface
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Virtual Machine', ('cluster_id', 'virtual_machine_id')),
         ('Virtual Machine', ('cluster_id', 'virtual_machine_id')),
         ('Attributes', ('enabled', 'mac_address', 'vrf_id')),
         ('Attributes', ('enabled', 'mac_address', 'vrf_id')),
     )
     )

+ 2 - 2
netbox/wireless/forms/filtersets.py

@@ -28,7 +28,7 @@ class WirelessLANGroupFilterForm(NetBoxModelFilterSetForm):
 class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = WirelessLAN
     model = WirelessLAN
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('ssid', 'group_id', 'status')),
         ('Attributes', ('ssid', 'group_id', 'status')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
         ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
@@ -67,7 +67,7 @@ class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
 class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = WirelessLink
     model = WirelessLink
     fieldsets = (
     fieldsets = (
-        (None, ('q', 'filter', 'tag')),
+        (None, ('q', 'filter_id', 'tag')),
         ('Attributes', ('ssid', 'status',)),
         ('Attributes', ('ssid', 'status',)),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Tenant', ('tenant_group_id', 'tenant_id')),
         ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
         ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),