Просмотр исходного кода

Closes #7886: Introduce a base FilterForm class

jeremystretch 4 лет назад
Родитель
Сommit
b7c9ca720a

+ 0 - 20
netbox/circuits/forms/filtersets.py

@@ -23,11 +23,6 @@ class ProviderFilterForm(CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id'],
         ['asn'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -63,11 +58,6 @@ class ProviderNetworkFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('provider_id',),
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     provider_id = DynamicModelMultipleChoiceField(
         queryset=Provider.objects.all(),
         required=False,
@@ -79,11 +69,6 @@ class ProviderNetworkFilterForm(CustomFieldModelFilterForm):
 
 class CircuitTypeFilterForm(CustomFieldModelFilterForm):
     model = CircuitType
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -96,11 +81,6 @@ class CircuitFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     type_id = DynamicModelMultipleChoiceField(
         queryset=CircuitType.objects.all(),
         required=False,

+ 4 - 104
netbox/dcim/forms/filtersets.py

@@ -9,7 +9,7 @@ from extras.forms import CustomFieldModelFilterForm, LocalConfigContextFilterFor
 from ipam.models import ASN
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
-    APISelectMultiple, add_blank_choice, BootstrapMixin, ColorField, DynamicModelMultipleChoiceField, StaticSelect,
+    APISelectMultiple, add_blank_choice, ColorField, DynamicModelMultipleChoiceField, FilterForm, StaticSelect,
     StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
 )
 from wireless.choices import *
@@ -51,11 +51,6 @@ class DeviceComponentFilterForm(CustomFieldModelFilterForm):
     field_order = [
         'q', 'name', 'label', 'region_id', 'site_group_id', 'site_id',
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     name = forms.CharField(
         required=False
     )
@@ -114,11 +109,6 @@ class DeviceComponentFilterForm(CustomFieldModelFilterForm):
 
 class RegionFilterForm(CustomFieldModelFilterForm):
     model = Region
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -130,11 +120,6 @@ class RegionFilterForm(CustomFieldModelFilterForm):
 
 class SiteGroupFilterForm(CustomFieldModelFilterForm):
     model = SiteGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent_id = DynamicModelMultipleChoiceField(
         queryset=SiteGroup.objects.all(),
         required=False,
@@ -153,11 +138,6 @@ class SiteFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['tenant_group_id', 'tenant_id'],
         ['asn_id']
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     status = forms.MultipleChoiceField(
         choices=SiteStatusChoices,
         required=False,
@@ -191,11 +171,6 @@ class LocationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id', 'parent_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -233,11 +208,6 @@ class LocationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
 
 class RackRoleFilterForm(CustomFieldModelFilterForm):
     model = RackRole
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -251,11 +221,6 @@ class RackFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['type', 'width', 'serial', 'asset_tag'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -338,11 +303,6 @@ class RackReservationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_id', 'location_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -379,11 +339,6 @@ class RackReservationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
 
 class ManufacturerFilterForm(CustomFieldModelFilterForm):
     model = Manufacturer
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -394,11 +349,6 @@ class DeviceTypeFilterForm(CustomFieldModelFilterForm):
         ['manufacturer_id', 'subdevice_role', 'airflow'],
         ['console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         required=False,
@@ -462,21 +412,11 @@ class DeviceTypeFilterForm(CustomFieldModelFilterForm):
 
 class DeviceRoleFilterForm(CustomFieldModelFilterForm):
     model = DeviceRole
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
 class PlatformFilterForm(CustomFieldModelFilterForm):
     model = Platform
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         required=False,
@@ -503,11 +443,6 @@ class DeviceFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFi
             'power_outlets', 'interfaces', 'pass_through_ports', 'local_context_data',
         ],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -666,11 +601,6 @@ class VirtualChassisFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -704,11 +634,6 @@ class CableFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['type', 'status', 'color'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -767,11 +692,6 @@ class PowerPanelFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('region_id', 'site_group_id', 'site_id', 'location_id')
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -815,11 +735,6 @@ class PowerFeedFilterForm(CustomFieldModelFilterForm):
         ['power_panel_id', 'rack_id'],
         ['status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1112,12 +1027,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
 # Connections
 #
 
-class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
+class ConsoleConnectionFilterForm(FilterForm):
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1144,12 +1054,7 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
+class PowerConnectionFilterForm(FilterForm):
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1176,12 +1081,7 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
+class InterfaceConnectionFilterForm(FilterForm):
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,

+ 2 - 2
netbox/extras/forms/customfields.py

@@ -4,7 +4,7 @@ from django.db.models import Q
 
 from extras.choices import *
 from extras.models import *
-from utilities.forms import BootstrapMixin, BulkEditForm, CSVModelForm
+from utilities.forms import BootstrapMixin, BulkEditForm, CSVModelForm, FilterForm
 
 __all__ = (
     'CustomFieldModelCSVForm',
@@ -105,7 +105,7 @@ class CustomFieldModelBulkEditForm(BulkEditForm):
             self.custom_fields.append(cf.name)
 
 
-class CustomFieldModelFilterForm(BootstrapMixin, forms.Form):
+class CustomFieldModelFilterForm(FilterForm):
 
     def __init__(self, *args, **kwargs):
 

+ 10 - 50
netbox/extras/forms/filtersets.py

@@ -9,9 +9,8 @@ from extras.models import *
 from extras.utils import FeatureQuery
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import (
-    add_blank_choice, APISelectMultiple, BootstrapMixin, ContentTypeChoiceField,
-    ContentTypeMultipleChoiceField, DateTimePicker, DynamicModelMultipleChoiceField, StaticSelect,
-    StaticSelectMultiple, BOOLEAN_WITH_BLANK_CHOICES,
+    add_blank_choice, APISelectMultiple, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DateTimePicker,
+    DynamicModelMultipleChoiceField, FilterForm, StaticSelect, StaticSelectMultiple, BOOLEAN_WITH_BLANK_CHOICES,
 )
 from virtualization.models import Cluster, ClusterGroup
 
@@ -28,17 +27,12 @@ __all__ = (
 )
 
 
-class CustomFieldFilterForm(BootstrapMixin, forms.Form):
+class CustomFieldFilterForm(FilterForm):
     field_groups = [
         ['q'],
         ['type', 'content_types'],
         ['weight', 'required'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     content_types = ContentTypeMultipleChoiceField(
         queryset=ContentType.objects.all(),
         limit_choices_to=FeatureQuery('custom_fields'),
@@ -61,16 +55,11 @@ class CustomFieldFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class CustomLinkFilterForm(BootstrapMixin, forms.Form):
+class CustomLinkFilterForm(FilterForm):
     field_groups = [
         ['q'],
         ['content_type', 'weight', 'new_window'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     content_type = ContentTypeChoiceField(
         queryset=ContentType.objects.all(),
         limit_choices_to=FeatureQuery('custom_fields'),
@@ -87,16 +76,11 @@ class CustomLinkFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class ExportTemplateFilterForm(BootstrapMixin, forms.Form):
+class ExportTemplateFilterForm(FilterForm):
     field_groups = [
         ['q'],
         ['content_type', 'mime_type', 'file_extension', 'as_attachment'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     content_type = ContentTypeChoiceField(
         queryset=ContentType.objects.all(),
         limit_choices_to=FeatureQuery('custom_fields'),
@@ -117,17 +101,12 @@ class ExportTemplateFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class WebhookFilterForm(BootstrapMixin, forms.Form):
+class WebhookFilterForm(FilterForm):
     field_groups = [
         ['q'],
         ['content_types', 'http_method', 'enabled'],
         ['type_create', 'type_update', 'type_delete'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     content_types = ContentTypeMultipleChoiceField(
         queryset=ContentType.objects.all(),
         limit_choices_to=FeatureQuery('custom_fields'),
@@ -165,12 +144,8 @@ class WebhookFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class TagFilterForm(BootstrapMixin, forms.Form):
+class TagFilterForm(FilterForm):
     model = Tag
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     content_type_id = ContentTypeMultipleChoiceField(
         queryset=ContentType.objects.filter(FeatureQuery('tags').get_query()),
         required=False,
@@ -178,7 +153,7 @@ class TagFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class ConfigContextFilterForm(BootstrapMixin, forms.Form):
+class ConfigContextFilterForm(FilterForm):
     field_groups = [
         ['q', 'tag'],
         ['region_id', 'site_group_id', 'site_id'],
@@ -186,11 +161,6 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form):
         ['cluster_group_id', 'cluster_id'],
         ['tenant_group_id', 'tenant_id']
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -270,18 +240,13 @@ class LocalConfigContextFilterForm(forms.Form):
     )
 
 
-class JournalEntryFilterForm(BootstrapMixin, forms.Form):
+class JournalEntryFilterForm(FilterForm):
     model = JournalEntry
     field_groups = [
         ['q'],
         ['created_before', 'created_after', 'created_by_id'],
         ['assigned_object_type_id', 'kind']
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     created_after = forms.DateTimeField(
         required=False,
         label=_('After'),
@@ -317,18 +282,13 @@ class JournalEntryFilterForm(BootstrapMixin, forms.Form):
     )
 
 
-class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
+class ObjectChangeFilterForm(FilterForm):
     model = ObjectChange
     field_groups = [
         ['q'],
         ['time_before', 'time_after', 'action'],
         ['user_id', 'changed_object_type_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     time_after = forms.DateTimeField(
         required=False,
         label=_('After'),

+ 0 - 65
netbox/ipam/forms/filtersets.py

@@ -45,11 +45,6 @@ class VRFFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['import_target_id', 'export_target_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     import_target_id = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         required=False,
@@ -72,11 +67,6 @@ class RouteTargetFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['importing_vrf_id', 'exporting_vrf_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     importing_vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         required=False,
@@ -94,11 +84,6 @@ class RouteTargetFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
 
 class RIRFilterForm(CustomFieldModelFilterForm):
     model = RIR
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     is_private = forms.NullBooleanField(
         required=False,
         label=_('Private'),
@@ -116,11 +101,6 @@ class AggregateFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['family', 'rir_id'],
         ['tenant_group_id', 'tenant_id']
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     family = forms.ChoiceField(
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
@@ -144,11 +124,6 @@ class ASNFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['tenant_group_id', 'tenant_id'],
         ['site_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     rir_id = DynamicModelMultipleChoiceField(
         queryset=RIR.objects.all(),
         required=False,
@@ -165,11 +140,6 @@ class ASNFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
 
 class RoleFilterForm(CustomFieldModelFilterForm):
     model = Role
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -182,11 +152,6 @@ class PrefixFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id'],
         ['tenant_group_id', 'tenant_id']
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     mask_length__lte = forms.IntegerField(
         widget=forms.HiddenInput()
     )
@@ -282,11 +247,6 @@ class IPRangeFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['family', 'vrf_id', 'status', 'role_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     family = forms.ChoiceField(
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
@@ -327,11 +287,6 @@ class IPAddressFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['vrf_id', 'present_in_vrf_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent = forms.CharField(
         required=False,
         widget=forms.TextInput(
@@ -393,11 +348,6 @@ class FHRPGroupFilterForm(CustomFieldModelFilterForm):
         ('protocol', 'group_id'),
         ('auth_type', 'auth_key'),
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     protocol = forms.MultipleChoiceField(
         choices=FHRPGroupProtocolChoices,
         required=False,
@@ -427,11 +377,6 @@ class VLANGroupFilterForm(CustomFieldModelFilterForm):
         ['region', 'sitegroup', 'site', 'location', 'rack']
     ]
     model = VLANGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -473,11 +418,6 @@ class VLANFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['group_id', 'status', 'role_id', 'vid'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -535,11 +475,6 @@ class ServiceFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('protocol', 'port'),
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     protocol = forms.ChoiceField(
         choices=add_blank_choice(ServiceProtocolChoices),
         required=False,

+ 0 - 25
netbox/tenancy/forms/filtersets.py

@@ -20,11 +20,6 @@ __all__ = (
 
 class TenantGroupFilterForm(CustomFieldModelFilterForm):
     model = TenantGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         required=False,
@@ -40,11 +35,6 @@ class TenantFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('group_id',),
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     group_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         required=False,
@@ -61,11 +51,6 @@ class TenantFilterForm(CustomFieldModelFilterForm):
 
 class ContactGroupFilterForm(CustomFieldModelFilterForm):
     model = ContactGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent_id = DynamicModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         required=False,
@@ -77,11 +62,6 @@ class ContactGroupFilterForm(CustomFieldModelFilterForm):
 
 class ContactRoleFilterForm(CustomFieldModelFilterForm):
     model = ContactRole
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -91,11 +71,6 @@ class ContactFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('group_id',),
     )
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     group_id = DynamicModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         required=False,

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

@@ -3,6 +3,7 @@ import re
 
 import yaml
 from django import forms
+from django.utils.translation import gettext as _
 
 from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSelect
 
@@ -13,6 +14,7 @@ __all__ = (
     'BulkRenameForm',
     'ConfirmationForm',
     'CSVModelForm',
+    'FilterForm',
     'ImportForm',
     'ReturnURLForm',
     'TableConfigForm',
@@ -177,6 +179,19 @@ class ImportForm(BootstrapMixin, forms.Form):
                 })
 
 
+class FilterForm(BootstrapMixin, forms.Form):
+    """
+    Base Form class for FilterSet forms.
+    """
+    q = forms.CharField(
+        required=False,
+        widget=forms.TextInput(
+            attrs={'placeholder': _('All fields')}
+        ),
+        label=_('Search')
+    )
+
+
 class TableConfigForm(BootstrapMixin, forms.Form):
     """
     Form for configuring user's table preferences.

+ 2 - 28
netbox/virtualization/forms/filtersets.py

@@ -5,8 +5,7 @@ from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
 from extras.forms import CustomFieldModelFilterForm, LocalConfigContextFilterForm
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
-    BootstrapMixin, DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple, TagFilterField,
-    BOOLEAN_WITH_BLANK_CHOICES,
+    DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
 )
 from virtualization.choices import *
 from virtualization.models import *
@@ -22,21 +21,11 @@ __all__ = (
 
 class ClusterTypeFilterForm(CustomFieldModelFilterForm):
     model = ClusterType
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
 class ClusterGroupFilterForm(CustomFieldModelFilterForm):
     model = ClusterGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     tag = TagFilterField(model)
 
 
@@ -51,11 +40,6 @@ class ClusterFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
         ['region_id', 'site_group_id', 'site_id'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     type_id = DynamicModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         required=False,
@@ -104,11 +88,6 @@ class VirtualMachineFilterForm(LocalConfigContextFilterForm, TenancyFilterForm,
         ['status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data'],
         ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     cluster_group_id = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         required=False,
@@ -188,18 +167,13 @@ class VirtualMachineFilterForm(LocalConfigContextFilterForm, TenancyFilterForm,
     tag = TagFilterField(model)
 
 
-class VMInterfaceFilterForm(BootstrapMixin, forms.Form):
+class VMInterfaceFilterForm(CustomFieldModelFilterForm):
     model = VMInterface
     field_groups = [
         ['q', 'tag'],
         ['cluster_id', 'virtual_machine_id'],
         ['enabled', 'mac_address'],
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         required=False,

+ 0 - 15
netbox/wireless/forms/filtersets.py

@@ -16,11 +16,6 @@ __all__ = (
 
 class WirelessLANGroupFilterForm(CustomFieldModelFilterForm):
     model = WirelessLANGroup
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     parent_id = DynamicModelMultipleChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         required=False,
@@ -36,11 +31,6 @@ class WirelessLANFilterForm(CustomFieldModelFilterForm):
         ('q', 'tag'),
         ('group_id',),
     ]
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     ssid = forms.CharField(
         required=False,
         label='SSID'
@@ -70,11 +60,6 @@ class WirelessLANFilterForm(CustomFieldModelFilterForm):
 
 class WirelessLinkFilterForm(CustomFieldModelFilterForm):
     model = WirelessLink
-    q = forms.CharField(
-        required=False,
-        widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
-        label=_('Search')
-    )
     ssid = forms.CharField(
         required=False,
         label='SSID'