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

Establish 4 core forms in netbox.forms.base

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

+ 10 - 0
docs/plugins/development/forms.md

@@ -0,0 +1,10 @@
+# Forms
+
+NetBox provides several base form classes for use by plugins. These are documented below.
+
+* `NetBoxModelForm`
+* `NetBoxModelCSVForm`
+* `NetBoxModelBulkEditForm`
+* `NetBoxModelFilterSetForm`
+
+### TODO: Include forms reference

+ 1 - 0
mkdocs.yml

@@ -105,6 +105,7 @@ nav:
             - Models: 'plugins/development/models.md'
             - Models: 'plugins/development/models.md'
             - Views: 'plugins/development/views.md'
             - Views: 'plugins/development/views.md'
             - Tables: 'plugins/development/tables.md'
             - Tables: 'plugins/development/tables.md'
+            - Forms: 'plugins/development/forms.md'
             - Filter Sets: 'plugins/development/filtersets.md'
             - Filter Sets: 'plugins/development/filtersets.md'
             - REST API: 'plugins/development/rest-api.md'
             - REST API: 'plugins/development/rest-api.md'
             - Background Tasks: 'plugins/development/background-tasks.md'
             - Background Tasks: 'plugins/development/background-tasks.md'

+ 5 - 5
netbox/circuits/forms/bulk_edit.py

@@ -2,7 +2,7 @@ from django import forms
 
 
 from circuits.choices import CircuitStatusChoices
 from circuits.choices import CircuitStatusChoices
 from circuits.models import *
 from circuits.models import *
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
+from netbox.forms import NetBoxModelBulkEditForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import add_blank_choice, CommentField, DynamicModelChoiceField, SmallTextarea, StaticSelect
 from utilities.forms import add_blank_choice, CommentField, DynamicModelChoiceField, SmallTextarea, StaticSelect
 
 
@@ -14,7 +14,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ProviderBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ProviderBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -53,7 +53,7 @@ class ProviderBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class ProviderNetworkBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ProviderNetwork.objects.all(),
         queryset=ProviderNetwork.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -81,7 +81,7 @@ class ProviderNetworkBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditFor
         ]
         ]
 
 
 
 
-class CircuitTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=CircuitType.objects.all(),
         queryset=CircuitType.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -95,7 +95,7 @@ class CircuitTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class CircuitBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class CircuitBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Circuit.objects.all(),
         queryset=Circuit.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput

+ 5 - 5
netbox/circuits/forms/bulk_import.py

@@ -1,6 +1,6 @@
 from circuits.choices import CircuitStatusChoices
 from circuits.choices import CircuitStatusChoices
 from circuits.models import *
 from circuits.models import *
-from extras.forms import CustomFieldModelCSVForm
+from netbox.forms import NetBoxModelCSVForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 
 
@@ -12,7 +12,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ProviderCSVForm(CustomFieldModelCSVForm):
+class ProviderCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -22,7 +22,7 @@ class ProviderCSVForm(CustomFieldModelCSVForm):
         )
         )
 
 
 
 
-class ProviderNetworkCSVForm(CustomFieldModelCSVForm):
+class ProviderNetworkCSVForm(NetBoxModelCSVForm):
     provider = CSVModelChoiceField(
     provider = CSVModelChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -36,7 +36,7 @@ class ProviderNetworkCSVForm(CustomFieldModelCSVForm):
         ]
         ]
 
 
 
 
-class CircuitTypeCSVForm(CustomFieldModelCSVForm):
+class CircuitTypeCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -47,7 +47,7 @@ class CircuitTypeCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class CircuitCSVForm(CustomFieldModelCSVForm):
+class CircuitCSVForm(NetBoxModelCSVForm):
     provider = CSVModelChoiceField(
     provider = CSVModelChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
         to_field_name='name',
         to_field_name='name',

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

@@ -4,7 +4,7 @@ from django.utils.translation import gettext as _
 from circuits.choices import CircuitStatusChoices
 from circuits.choices import CircuitStatusChoices
 from circuits.models import *
 from circuits.models import *
 from dcim.models import Region, Site, SiteGroup
 from dcim.models import Region, Site, SiteGroup
-from extras.forms import CustomFieldModelFilterForm
+from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.forms import TenancyFilterForm
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import DynamicModelMultipleChoiceField, StaticSelectMultiple, TagFilterField
 from utilities.forms import DynamicModelMultipleChoiceField, StaticSelectMultiple, TagFilterField
 
 
@@ -16,7 +16,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ProviderFilterForm(CustomFieldModelFilterForm):
+class ProviderFilterForm(NetBoxModelFilterSetForm):
     model = Provider
     model = Provider
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -49,7 +49,7 @@ class ProviderFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ProviderNetworkFilterForm(CustomFieldModelFilterForm):
+class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
     model = ProviderNetwork
     model = ProviderNetwork
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),
@@ -67,12 +67,12 @@ class ProviderNetworkFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class CircuitTypeFilterForm(CustomFieldModelFilterForm):
+class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
     model = CircuitType
     model = CircuitType
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class CircuitFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class CircuitFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Circuit
     model = Circuit
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],

+ 5 - 5
netbox/circuits/forms/models.py

@@ -2,8 +2,8 @@ from django import forms
 
 
 from circuits.models import *
 from circuits.models import *
 from dcim.models import Region, Site, SiteGroup
 from dcim.models import Region, Site, SiteGroup
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
+from netbox.forms import NetBoxModelForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from utilities.forms import (
 from utilities.forms import (
     BootstrapMixin, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
     BootstrapMixin, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
@@ -19,7 +19,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ProviderForm(CustomFieldModelForm):
+class ProviderForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     comments = CommentField()
     comments = CommentField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
@@ -53,7 +53,7 @@ class ProviderForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class ProviderNetworkForm(CustomFieldModelForm):
+class ProviderNetworkForm(NetBoxModelForm):
     provider = DynamicModelChoiceField(
     provider = DynamicModelChoiceField(
         queryset=Provider.objects.all()
         queryset=Provider.objects.all()
     )
     )
@@ -73,7 +73,7 @@ class ProviderNetworkForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class CircuitTypeForm(CustomFieldModelForm):
+class CircuitTypeForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -87,7 +87,7 @@ class CircuitTypeForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class CircuitForm(TenancyForm, CustomFieldModelForm):
+class CircuitForm(TenancyForm, NetBoxModelForm):
     provider = DynamicModelChoiceField(
     provider = DynamicModelChoiceField(
         queryset=Provider.objects.all()
         queryset=Provider.objects.all()
     )
     )

+ 30 - 40
netbox/dcim/forms/bulk_edit.py

@@ -6,8 +6,8 @@ from timezone_field import TimeZoneFormField
 from dcim.choices import *
 from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import *
 from dcim.models import *
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
 from ipam.models import ASN, VLAN, VRF
 from ipam.models import ASN, VLAN, VRF
+from netbox.forms import NetBoxModelBulkEditForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, BulkEditForm, BulkEditNullBooleanSelect, ColorField, CommentField, DynamicModelChoiceField,
     add_blank_choice, BulkEditForm, BulkEditNullBooleanSelect, ColorField, CommentField, DynamicModelChoiceField,
@@ -57,7 +57,7 @@ __all__ = (
 )
 )
 
 
 
 
-class RegionBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RegionBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -75,7 +75,7 @@ class RegionBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['parent', 'description']
         nullable_fields = ['parent', 'description']
 
 
 
 
-class SiteGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class SiteGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=SiteGroup.objects.all(),
         queryset=SiteGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -93,7 +93,7 @@ class SiteGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['parent', 'description']
         nullable_fields = ['parent', 'description']
 
 
 
 
-class SiteBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class SiteBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -137,7 +137,7 @@ class SiteBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class LocationBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class LocationBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Location.objects.all(),
         queryset=Location.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -166,7 +166,7 @@ class LocationBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['parent', 'tenant', 'description']
         nullable_fields = ['parent', 'tenant', 'description']
 
 
 
 
-class RackRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RackRoleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=RackRole.objects.all(),
         queryset=RackRole.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -183,7 +183,7 @@ class RackRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['color', 'description']
         nullable_fields = ['color', 'description']
 
 
 
 
-class RackBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RackBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -283,7 +283,7 @@ class RackBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class RackReservationBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=RackReservation.objects.all(),
         queryset=RackReservation.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -308,7 +308,7 @@ class RackReservationBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditFor
         nullable_fields = []
         nullable_fields = []
 
 
 
 
-class ManufacturerBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -322,7 +322,7 @@ class ManufacturerBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class DeviceTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -353,7 +353,7 @@ class DeviceTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['part_number', 'airflow']
         nullable_fields = ['part_number', 'airflow']
 
 
 
 
-class ModuleTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ModuleType.objects.all(),
         queryset=ModuleType.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -370,7 +370,7 @@ class ModuleTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['part_number']
         nullable_fields = ['part_number']
 
 
 
 
-class DeviceRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -392,7 +392,7 @@ class DeviceRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['color', 'description']
         nullable_fields = ['color', 'description']
 
 
 
 
-class PlatformBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class PlatformBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -415,7 +415,7 @@ class PlatformBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['manufacturer', 'napalm_driver', 'description']
         nullable_fields = ['manufacturer', 'napalm_driver', 'description']
 
 
 
 
-class DeviceBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class DeviceBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -476,7 +476,7 @@ class DeviceBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class ModuleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ModuleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Module.objects.all(),
         queryset=Module.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -502,7 +502,7 @@ class ModuleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['serial']
         nullable_fields = ['serial']
 
 
 
 
-class CableBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class CableBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Cable.objects.all(),
         queryset=Cable.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -558,7 +558,7 @@ class CableBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
             })
             })
 
 
 
 
-class VirtualChassisBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VirtualChassis.objects.all(),
         queryset=VirtualChassis.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -572,7 +572,7 @@ class VirtualChassisBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm
         nullable_fields = ['domain']
         nullable_fields = ['domain']
 
 
 
 
-class PowerPanelBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=PowerPanel.objects.all(),
         queryset=PowerPanel.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -611,7 +611,7 @@ class PowerPanelBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['location']
         nullable_fields = ['location']
 
 
 
 
-class PowerFeedBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=PowerFeed.objects.all(),
         queryset=PowerFeed.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -939,8 +939,7 @@ class InventoryItemTemplateBulkEditForm(BulkEditForm):
 
 
 class ConsolePortBulkEditForm(
 class ConsolePortBulkEditForm(
     form_from_model(ConsolePort, ['label', 'type', 'speed', 'mark_connected', 'description']),
     form_from_model(ConsolePort, ['label', 'type', 'speed', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ConsolePort.objects.all(),
         queryset=ConsolePort.objects.all(),
@@ -957,8 +956,7 @@ class ConsolePortBulkEditForm(
 
 
 class ConsoleServerPortBulkEditForm(
 class ConsoleServerPortBulkEditForm(
     form_from_model(ConsoleServerPort, ['label', 'type', 'speed', 'mark_connected', 'description']),
     form_from_model(ConsoleServerPort, ['label', 'type', 'speed', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ConsoleServerPort.objects.all(),
         queryset=ConsoleServerPort.objects.all(),
@@ -975,8 +973,7 @@ class ConsoleServerPortBulkEditForm(
 
 
 class PowerPortBulkEditForm(
 class PowerPortBulkEditForm(
     form_from_model(PowerPort, ['label', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected', 'description']),
     form_from_model(PowerPort, ['label', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=PowerPort.objects.all(),
         queryset=PowerPort.objects.all(),
@@ -993,8 +990,7 @@ class PowerPortBulkEditForm(
 
 
 class PowerOutletBulkEditForm(
 class PowerOutletBulkEditForm(
     form_from_model(PowerOutlet, ['label', 'type', 'feed_leg', 'power_port', 'mark_connected', 'description']),
     form_from_model(PowerOutlet, ['label', 'type', 'feed_leg', 'power_port', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=PowerOutlet.objects.all(),
         queryset=PowerOutlet.objects.all(),
@@ -1031,8 +1027,7 @@ class InterfaceBulkEditForm(
         'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected',
         'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected',
         'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
         'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
     ]),
     ]),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Interface.objects.all(),
         queryset=Interface.objects.all(),
@@ -1154,8 +1149,7 @@ class InterfaceBulkEditForm(
 
 
 class FrontPortBulkEditForm(
 class FrontPortBulkEditForm(
     form_from_model(FrontPort, ['label', 'type', 'color', 'mark_connected', 'description']),
     form_from_model(FrontPort, ['label', 'type', 'color', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=FrontPort.objects.all(),
         queryset=FrontPort.objects.all(),
@@ -1168,8 +1162,7 @@ class FrontPortBulkEditForm(
 
 
 class RearPortBulkEditForm(
 class RearPortBulkEditForm(
     form_from_model(RearPort, ['label', 'type', 'color', 'mark_connected', 'description']),
     form_from_model(RearPort, ['label', 'type', 'color', 'mark_connected', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=RearPort.objects.all(),
         queryset=RearPort.objects.all(),
@@ -1182,8 +1175,7 @@ class RearPortBulkEditForm(
 
 
 class ModuleBayBulkEditForm(
 class ModuleBayBulkEditForm(
     form_from_model(DeviceBay, ['label', 'description']),
     form_from_model(DeviceBay, ['label', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ModuleBay.objects.all(),
         queryset=ModuleBay.objects.all(),
@@ -1196,8 +1188,7 @@ class ModuleBayBulkEditForm(
 
 
 class DeviceBayBulkEditForm(
 class DeviceBayBulkEditForm(
     form_from_model(DeviceBay, ['label', 'description']),
     form_from_model(DeviceBay, ['label', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=DeviceBay.objects.all(),
         queryset=DeviceBay.objects.all(),
@@ -1210,8 +1201,7 @@ class DeviceBayBulkEditForm(
 
 
 class InventoryItemBulkEditForm(
 class InventoryItemBulkEditForm(
     form_from_model(InventoryItem, ['label', 'role', 'manufacturer', 'part_id', 'description']),
     form_from_model(InventoryItem, ['label', 'role', 'manufacturer', 'part_id', 'description']),
-    AddRemoveTagsForm,
-    CustomFieldModelBulkEditForm
+    NetBoxModelBulkEditForm
 ):
 ):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=InventoryItem.objects.all(),
         queryset=InventoryItem.objects.all(),
@@ -1234,7 +1224,7 @@ class InventoryItemBulkEditForm(
 # Device component roles
 # Device component roles
 #
 #
 
 
-class InventoryItemRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=InventoryItemRole.objects.all(),
         queryset=InventoryItemRole.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput

+ 28 - 28
netbox/dcim/forms/bulk_import.py

@@ -7,8 +7,8 @@ from django.utils.safestring import mark_safe
 from dcim.choices import *
 from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import *
 from dcim.models import *
-from extras.forms import CustomFieldModelCSVForm
 from ipam.models import VRF
 from ipam.models import VRF
+from netbox.forms import NetBoxModelCSVForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField
 from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVTypedChoiceField, SlugField
 from virtualization.models import Cluster
 from virtualization.models import Cluster
@@ -46,7 +46,7 @@ __all__ = (
 )
 )
 
 
 
 
-class RegionCSVForm(CustomFieldModelCSVForm):
+class RegionCSVForm(NetBoxModelCSVForm):
     parent = CSVModelChoiceField(
     parent = CSVModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -59,7 +59,7 @@ class RegionCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'parent', 'description')
         fields = ('name', 'slug', 'parent', 'description')
 
 
 
 
-class SiteGroupCSVForm(CustomFieldModelCSVForm):
+class SiteGroupCSVForm(NetBoxModelCSVForm):
     parent = CSVModelChoiceField(
     parent = CSVModelChoiceField(
         queryset=SiteGroup.objects.all(),
         queryset=SiteGroup.objects.all(),
         required=False,
         required=False,
@@ -72,7 +72,7 @@ class SiteGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'parent', 'description')
         fields = ('name', 'slug', 'parent', 'description')
 
 
 
 
-class SiteCSVForm(CustomFieldModelCSVForm):
+class SiteCSVForm(NetBoxModelCSVForm):
     status = CSVChoiceField(
     status = CSVChoiceField(
         choices=SiteStatusChoices,
         choices=SiteStatusChoices,
         help_text='Operational status'
         help_text='Operational status'
@@ -109,7 +109,7 @@ class SiteCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class LocationCSVForm(CustomFieldModelCSVForm):
+class LocationCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -136,7 +136,7 @@ class LocationCSVForm(CustomFieldModelCSVForm):
         fields = ('site', 'parent', 'name', 'slug', 'tenant', 'description')
         fields = ('site', 'parent', 'name', 'slug', 'tenant', 'description')
 
 
 
 
-class RackRoleCSVForm(CustomFieldModelCSVForm):
+class RackRoleCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -147,7 +147,7 @@ class RackRoleCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class RackCSVForm(CustomFieldModelCSVForm):
+class RackCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -205,7 +205,7 @@ class RackCSVForm(CustomFieldModelCSVForm):
             self.fields['location'].queryset = self.fields['location'].queryset.filter(**params)
             self.fields['location'].queryset = self.fields['location'].queryset.filter(**params)
 
 
 
 
-class RackReservationCSVForm(CustomFieldModelCSVForm):
+class RackReservationCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -255,14 +255,14 @@ class RackReservationCSVForm(CustomFieldModelCSVForm):
             self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
             self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
 
 
 
 
-class ManufacturerCSVForm(CustomFieldModelCSVForm):
+class ManufacturerCSVForm(NetBoxModelCSVForm):
 
 
     class Meta:
     class Meta:
         model = Manufacturer
         model = Manufacturer
         fields = ('name', 'slug', 'description')
         fields = ('name', 'slug', 'description')
 
 
 
 
-class DeviceRoleCSVForm(CustomFieldModelCSVForm):
+class DeviceRoleCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -273,7 +273,7 @@ class DeviceRoleCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class PlatformCSVForm(CustomFieldModelCSVForm):
+class PlatformCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
     manufacturer = CSVModelChoiceField(
     manufacturer = CSVModelChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
@@ -287,7 +287,7 @@ class PlatformCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description')
         fields = ('name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description')
 
 
 
 
-class BaseDeviceCSVForm(CustomFieldModelCSVForm):
+class BaseDeviceCSVForm(NetBoxModelCSVForm):
     device_role = CSVModelChoiceField(
     device_role = CSVModelChoiceField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -403,7 +403,7 @@ class DeviceCSVForm(BaseDeviceCSVForm):
             self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
             self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
 
 
 
 
-class ModuleCSVForm(CustomFieldModelCSVForm):
+class ModuleCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -478,7 +478,7 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm):
 # Device components
 # Device components
 #
 #
 
 
-class ConsolePortCSVForm(CustomFieldModelCSVForm):
+class ConsolePortCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -501,7 +501,7 @@ class ConsolePortCSVForm(CustomFieldModelCSVForm):
         fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
         fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
 
 
 
 
-class ConsoleServerPortCSVForm(CustomFieldModelCSVForm):
+class ConsoleServerPortCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -524,7 +524,7 @@ class ConsoleServerPortCSVForm(CustomFieldModelCSVForm):
         fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
         fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
 
 
 
 
-class PowerPortCSVForm(CustomFieldModelCSVForm):
+class PowerPortCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -542,7 +542,7 @@ class PowerPortCSVForm(CustomFieldModelCSVForm):
         )
         )
 
 
 
 
-class PowerOutletCSVForm(CustomFieldModelCSVForm):
+class PowerOutletCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -591,7 +591,7 @@ class PowerOutletCSVForm(CustomFieldModelCSVForm):
             self.fields['power_port'].queryset = PowerPort.objects.none()
             self.fields['power_port'].queryset = PowerPort.objects.none()
 
 
 
 
-class InterfaceCSVForm(CustomFieldModelCSVForm):
+class InterfaceCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -655,7 +655,7 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
             return self.cleaned_data['enabled']
             return self.cleaned_data['enabled']
 
 
 
 
-class FrontPortCSVForm(CustomFieldModelCSVForm):
+class FrontPortCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -703,7 +703,7 @@ class FrontPortCSVForm(CustomFieldModelCSVForm):
             self.fields['rear_port'].queryset = RearPort.objects.none()
             self.fields['rear_port'].queryset = RearPort.objects.none()
 
 
 
 
-class RearPortCSVForm(CustomFieldModelCSVForm):
+class RearPortCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -721,7 +721,7 @@ class RearPortCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class ModuleBayCSVForm(CustomFieldModelCSVForm):
+class ModuleBayCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -732,7 +732,7 @@ class ModuleBayCSVForm(CustomFieldModelCSVForm):
         fields = ('device', 'name', 'label', 'position', 'description')
         fields = ('device', 'name', 'label', 'position', 'description')
 
 
 
 
-class DeviceBayCSVForm(CustomFieldModelCSVForm):
+class DeviceBayCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -778,7 +778,7 @@ class DeviceBayCSVForm(CustomFieldModelCSVForm):
             self.fields['installed_device'].queryset = Interface.objects.none()
             self.fields['installed_device'].queryset = Interface.objects.none()
 
 
 
 
-class InventoryItemCSVForm(CustomFieldModelCSVForm):
+class InventoryItemCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name'
         to_field_name='name'
@@ -827,7 +827,7 @@ class InventoryItemCSVForm(CustomFieldModelCSVForm):
 # Device component roles
 # Device component roles
 #
 #
 
 
-class InventoryItemRoleCSVForm(CustomFieldModelCSVForm):
+class InventoryItemRoleCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -842,7 +842,7 @@ class InventoryItemRoleCSVForm(CustomFieldModelCSVForm):
 # Cables
 # Cables
 #
 #
 
 
-class CableCSVForm(CustomFieldModelCSVForm):
+class CableCSVForm(NetBoxModelCSVForm):
     # Termination A
     # Termination A
     side_a_device = CSVModelChoiceField(
     side_a_device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
@@ -947,7 +947,7 @@ class CableCSVForm(CustomFieldModelCSVForm):
 # Virtual chassis
 # Virtual chassis
 #
 #
 
 
-class VirtualChassisCSVForm(CustomFieldModelCSVForm):
+class VirtualChassisCSVForm(NetBoxModelCSVForm):
     master = CSVModelChoiceField(
     master = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -964,7 +964,7 @@ class VirtualChassisCSVForm(CustomFieldModelCSVForm):
 # Power
 # Power
 #
 #
 
 
-class PowerPanelCSVForm(CustomFieldModelCSVForm):
+class PowerPanelCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -990,7 +990,7 @@ class PowerPanelCSVForm(CustomFieldModelCSVForm):
             self.fields['location'].queryset = self.fields['location'].queryset.filter(**params)
             self.fields['location'].queryset = self.fields['location'].queryset.filter(**params)
 
 
 
 
-class PowerFeedCSVForm(CustomFieldModelCSVForm):
+class PowerFeedCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='name',
         to_field_name='name',

+ 4 - 4
netbox/dcim/forms/connections.py

@@ -1,7 +1,7 @@
 from circuits.models import Circuit, CircuitTermination, Provider
 from circuits.models import Circuit, CircuitTermination, Provider
 from dcim.models import *
 from dcim.models import *
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
+from netbox.forms import NetBoxModelForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect
 from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect
 
 
@@ -18,7 +18,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ConnectCableToDeviceForm(TenancyForm, CustomFieldModelForm):
+class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm):
     """
     """
     Base form for connecting a Cable to a Device component
     Base form for connecting a Cable to a Device component
     """
     """
@@ -171,7 +171,7 @@ class ConnectCableToRearPortForm(ConnectCableToDeviceForm):
     )
     )
 
 
 
 
-class ConnectCableToCircuitTerminationForm(TenancyForm, CustomFieldModelForm):
+class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm):
     termination_b_provider = DynamicModelChoiceField(
     termination_b_provider = DynamicModelChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
         label='Provider',
         label='Provider',
@@ -229,7 +229,7 @@ class ConnectCableToCircuitTerminationForm(TenancyForm, CustomFieldModelForm):
         return getattr(self.cleaned_data['termination_b_id'], 'pk', None)
         return getattr(self.cleaned_data['termination_b_id'], 'pk', None)
 
 
 
 
-class ConnectCableToPowerFeedForm(TenancyForm, CustomFieldModelForm):
+class ConnectCableToPowerFeedForm(TenancyForm, NetBoxModelForm):
     termination_b_region = DynamicModelChoiceField(
     termination_b_region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         label='Region',
         label='Region',

+ 22 - 21
netbox/dcim/forms/filtersets.py

@@ -5,8 +5,9 @@ from django.utils.translation import gettext as _
 from dcim.choices import *
 from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import *
 from dcim.models import *
-from extras.forms import CustomFieldModelFilterForm, LocalConfigContextFilterForm
+from extras.forms import LocalConfigContextFilterForm
 from ipam.models import ASN, VRF
 from ipam.models import ASN, VRF
+from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.forms import TenancyFilterForm
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
 from utilities.forms import (
     APISelectMultiple, add_blank_choice, ColorField, DynamicModelMultipleChoiceField, FilterForm, StaticSelect,
     APISelectMultiple, add_blank_choice, ColorField, DynamicModelMultipleChoiceField, FilterForm, StaticSelect,
@@ -52,7 +53,7 @@ __all__ = (
 )
 )
 
 
 
 
-class DeviceComponentFilterForm(CustomFieldModelFilterForm):
+class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
     name = forms.CharField(
     name = forms.CharField(
         required=False
         required=False
     )
     )
@@ -103,7 +104,7 @@ class DeviceComponentFilterForm(CustomFieldModelFilterForm):
     )
     )
 
 
 
 
-class RegionFilterForm(CustomFieldModelFilterForm):
+class RegionFilterForm(NetBoxModelFilterSetForm):
     model = Region
     model = Region
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -113,7 +114,7 @@ class RegionFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class SiteGroupFilterForm(CustomFieldModelFilterForm):
+class SiteGroupFilterForm(NetBoxModelFilterSetForm):
     model = SiteGroup
     model = SiteGroup
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=SiteGroup.objects.all(),
         queryset=SiteGroup.objects.all(),
@@ -123,7 +124,7 @@ class SiteGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class SiteFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class SiteFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Site
     model = Site
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -154,7 +155,7 @@ class SiteFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class LocationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class LocationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Location
     model = Location
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -192,12 +193,12 @@ class LocationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class RackRoleFilterForm(CustomFieldModelFilterForm):
+class RackRoleFilterForm(NetBoxModelFilterSetForm):
     model = RackRole
     model = RackRole
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class RackFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class RackFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Rack
     model = Rack
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -270,7 +271,7 @@ class RackElevationFilterForm(RackFilterForm):
     )
     )
 
 
 
 
-class RackReservationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = RackReservation
     model = RackReservation
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -308,12 +309,12 @@ class RackReservationFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ManufacturerFilterForm(CustomFieldModelFilterForm):
+class ManufacturerFilterForm(NetBoxModelFilterSetForm):
     model = Manufacturer
     model = Manufacturer
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class DeviceTypeFilterForm(CustomFieldModelFilterForm):
+class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
     model = DeviceType
     model = DeviceType
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -383,7 +384,7 @@ class DeviceTypeFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ModuleTypeFilterForm(CustomFieldModelFilterForm):
+class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
     model = ModuleType
     model = ModuleType
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -444,12 +445,12 @@ class ModuleTypeFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class DeviceRoleFilterForm(CustomFieldModelFilterForm):
+class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
     model = DeviceRole
     model = DeviceRole
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class PlatformFilterForm(CustomFieldModelFilterForm):
+class PlatformFilterForm(NetBoxModelFilterSetForm):
     model = Platform
     model = Platform
     manufacturer_id = DynamicModelMultipleChoiceField(
     manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
@@ -459,7 +460,7 @@ class PlatformFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class DeviceFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldModelFilterForm):
+class DeviceFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Device
     model = Device
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -613,7 +614,7 @@ class DeviceFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFi
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldModelFilterForm):
+class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Module
     model = Module
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -644,7 +645,7 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFi
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VirtualChassisFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VirtualChassis
     model = VirtualChassis
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -673,7 +674,7 @@ class VirtualChassisFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class CableFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Cable
     model = Cable
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -736,7 +737,7 @@ class CableFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class PowerPanelFilterForm(CustomFieldModelFilterForm):
+class PowerPanelFilterForm(NetBoxModelFilterSetForm):
     model = PowerPanel
     model = PowerPanel
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),
@@ -773,7 +774,7 @@ class PowerPanelFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class PowerFeedFilterForm(CustomFieldModelFilterForm):
+class PowerFeedFilterForm(NetBoxModelFilterSetForm):
     model = PowerFeed
     model = PowerFeed
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -1103,7 +1104,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
 # Device component roles
 # Device component roles
 #
 #
 
 
-class InventoryItemRoleFilterForm(CustomFieldModelFilterForm):
+class InventoryItemRoleFilterForm(NetBoxModelFilterSetForm):
     model = InventoryItemRole
     model = InventoryItemRole
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 

+ 30 - 30
netbox/dcim/forms/models.py

@@ -7,9 +7,9 @@ from timezone_field import TimeZoneFormField
 from dcim.choices import *
 from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import *
 from dcim.models import *
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
 from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF
 from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF
+from netbox.forms import NetBoxModelForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from utilities.forms import (
 from utilities.forms import (
     APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
     APISelect, add_blank_choice, BootstrapMixin, ClearableFileInput, CommentField, ContentTypeChoiceField,
@@ -72,7 +72,7 @@ Tagged (All): Implies all VLANs are available (w/optional untagged VLAN)
 """
 """
 
 
 
 
-class RegionForm(CustomFieldModelForm):
+class RegionForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False
         required=False
@@ -90,7 +90,7 @@ class RegionForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class SiteGroupForm(CustomFieldModelForm):
+class SiteGroupForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=SiteGroup.objects.all(),
         queryset=SiteGroup.objects.all(),
         required=False
         required=False
@@ -108,7 +108,7 @@ class SiteGroupForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class SiteForm(TenancyForm, CustomFieldModelForm):
+class SiteForm(TenancyForm, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False
         required=False
@@ -173,7 +173,7 @@ class SiteForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class LocationForm(TenancyForm, CustomFieldModelForm):
+class LocationForm(TenancyForm, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -221,7 +221,7 @@ class LocationForm(TenancyForm, CustomFieldModelForm):
         )
         )
 
 
 
 
-class RackRoleForm(CustomFieldModelForm):
+class RackRoleForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -235,7 +235,7 @@ class RackRoleForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class RackForm(TenancyForm, CustomFieldModelForm):
+class RackForm(TenancyForm, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -295,7 +295,7 @@ class RackForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class RackReservationForm(TenancyForm, CustomFieldModelForm):
+class RackReservationForm(TenancyForm, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -359,7 +359,7 @@ class RackReservationForm(TenancyForm, CustomFieldModelForm):
         )
         )
 
 
 
 
-class ManufacturerForm(CustomFieldModelForm):
+class ManufacturerForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -373,7 +373,7 @@ class ManufacturerForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class DeviceTypeForm(CustomFieldModelForm):
+class DeviceTypeForm(NetBoxModelForm):
     manufacturer = DynamicModelChoiceField(
     manufacturer = DynamicModelChoiceField(
         queryset=Manufacturer.objects.all()
         queryset=Manufacturer.objects.all()
     )
     )
@@ -412,7 +412,7 @@ class DeviceTypeForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class ModuleTypeForm(CustomFieldModelForm):
+class ModuleTypeForm(NetBoxModelForm):
     manufacturer = DynamicModelChoiceField(
     manufacturer = DynamicModelChoiceField(
         queryset=Manufacturer.objects.all()
         queryset=Manufacturer.objects.all()
     )
     )
@@ -429,7 +429,7 @@ class ModuleTypeForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class DeviceRoleForm(CustomFieldModelForm):
+class DeviceRoleForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -443,7 +443,7 @@ class DeviceRoleForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class PlatformForm(CustomFieldModelForm):
+class PlatformForm(NetBoxModelForm):
     manufacturer = DynamicModelChoiceField(
     manufacturer = DynamicModelChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
         required=False
         required=False
@@ -466,7 +466,7 @@ class PlatformForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class DeviceForm(TenancyForm, CustomFieldModelForm):
+class DeviceForm(TenancyForm, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -648,7 +648,7 @@ class DeviceForm(TenancyForm, CustomFieldModelForm):
             self.fields['position'].widget.choices = [(position, f'U{position}')]
             self.fields['position'].widget.choices = [(position, f'U{position}')]
 
 
 
 
-class ModuleForm(CustomFieldModelForm):
+class ModuleForm(NetBoxModelForm):
     device = DynamicModelChoiceField(
     device = DynamicModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
@@ -688,7 +688,7 @@ class ModuleForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class CableForm(TenancyForm, CustomFieldModelForm):
+class CableForm(TenancyForm, NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -711,7 +711,7 @@ class CableForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class PowerPanelForm(CustomFieldModelForm):
+class PowerPanelForm(NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -755,7 +755,7 @@ class PowerPanelForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class PowerFeedForm(CustomFieldModelForm):
+class PowerFeedForm(NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
@@ -823,7 +823,7 @@ class PowerFeedForm(CustomFieldModelForm):
 # Virtual chassis
 # Virtual chassis
 #
 #
 
 
-class VirtualChassisForm(CustomFieldModelForm):
+class VirtualChassisForm(NetBoxModelForm):
     master = forms.ModelChoiceField(
     master = forms.ModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
@@ -1120,7 +1120,7 @@ class InventoryItemTemplateForm(BootstrapMixin, forms.ModelForm):
 # Device components
 # Device components
 #
 #
 
 
-class ConsolePortForm(CustomFieldModelForm):
+class ConsolePortForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1138,7 +1138,7 @@ class ConsolePortForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class ConsoleServerPortForm(CustomFieldModelForm):
+class ConsoleServerPortForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1156,7 +1156,7 @@ class ConsoleServerPortForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class PowerPortForm(CustomFieldModelForm):
+class PowerPortForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1174,7 +1174,7 @@ class PowerPortForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class PowerOutletForm(CustomFieldModelForm):
+class PowerOutletForm(NetBoxModelForm):
     power_port = DynamicModelChoiceField(
     power_port = DynamicModelChoiceField(
         queryset=PowerPort.objects.all(),
         queryset=PowerPort.objects.all(),
         required=False,
         required=False,
@@ -1199,7 +1199,7 @@ class PowerOutletForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
+class InterfaceForm(InterfaceCommonForm, NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=Interface.objects.all(),
         queryset=Interface.objects.all(),
         required=False,
         required=False,
@@ -1308,7 +1308,7 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class FrontPortForm(CustomFieldModelForm):
+class FrontPortForm(NetBoxModelForm):
     rear_port = DynamicModelChoiceField(
     rear_port = DynamicModelChoiceField(
         queryset=RearPort.objects.all(),
         queryset=RearPort.objects.all(),
         query_params={
         query_params={
@@ -1332,7 +1332,7 @@ class FrontPortForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class RearPortForm(CustomFieldModelForm):
+class RearPortForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1349,7 +1349,7 @@ class RearPortForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class ModuleBayForm(CustomFieldModelForm):
+class ModuleBayForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1365,7 +1365,7 @@ class ModuleBayForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class DeviceBayForm(CustomFieldModelForm):
+class DeviceBayForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -1401,7 +1401,7 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
         ).exclude(pk=device_bay.device.pk)
         ).exclude(pk=device_bay.device.pk)
 
 
 
 
-class InventoryItemForm(CustomFieldModelForm):
+class InventoryItemForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=InventoryItem.objects.all(),
         queryset=InventoryItem.objects.all(),
         required=False,
         required=False,
@@ -1451,7 +1451,7 @@ class InventoryItemForm(CustomFieldModelForm):
 # Device component roles
 # Device component roles
 #
 #
 
 
-class InventoryItemRoleForm(CustomFieldModelForm):
+class InventoryItemRoleForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),

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

@@ -1,8 +1,8 @@
 from django import forms
 from django import forms
 
 
 from dcim.models import *
 from dcim.models import *
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
+from netbox.forms import NetBoxModelForm
 from utilities.forms import (
 from utilities.forms import (
     BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField,
     BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField,
 )
 )
@@ -149,7 +149,7 @@ class FrontPortCreateForm(DeviceComponentCreateForm):
         }
         }
 
 
 
 
-class VirtualChassisCreateForm(CustomFieldModelForm):
+class VirtualChassisCreateForm(NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,

+ 0 - 81
netbox/extras/forms/customfields.py

@@ -1,16 +1,8 @@
-from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.db.models import Q
 
 
-from extras.choices import *
 from extras.models import *
 from extras.models import *
-from utilities.forms import BootstrapMixin, BulkEditBaseForm, CSVModelForm
 
 
 __all__ = (
 __all__ = (
-    'CustomFieldModelCSVForm',
-    'CustomFieldModelBulkEditForm',
-    'CustomFieldModelFilterForm',
-    'CustomFieldModelForm',
     'CustomFieldsMixin',
     'CustomFieldsMixin',
 )
 )
 
 
@@ -50,76 +42,3 @@ class CustomFieldsMixin:
 
 
             # Annotate the field in the list of CustomField form fields
             # Annotate the field in the list of CustomField form fields
             self.custom_fields[field_name] = customfield
             self.custom_fields[field_name] = customfield
-
-
-class CustomFieldModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm):
-    """
-    Extend ModelForm to include custom field support.
-    """
-    def _get_content_type(self):
-        return ContentType.objects.get_for_model(self._meta.model)
-
-    def _get_form_field(self, customfield):
-        if self.instance.pk:
-            form_field = customfield.to_form_field(set_initial=False)
-            form_field.initial = self.instance.custom_field_data.get(customfield.name, None)
-            return form_field
-
-        return customfield.to_form_field()
-
-    def clean(self):
-
-        # Save custom field data on instance
-        for cf_name, customfield in self.custom_fields.items():
-            key = cf_name[3:]  # Strip "cf_" from field name
-            value = self.cleaned_data.get(cf_name)
-
-            # Convert "empty" values to null
-            if value in self.fields[cf_name].empty_values:
-                self.instance.custom_field_data[key] = None
-            else:
-                self.instance.custom_field_data[key] = customfield.serialize(value)
-
-        return super().clean()
-
-
-class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelForm):
-
-    def _get_form_field(self, customfield):
-        return customfield.to_form_field(for_csv_import=True)
-
-
-class CustomFieldModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditBaseForm):
-
-    def _get_form_field(self, customfield):
-        return customfield.to_form_field(set_initial=False, enforce_required=False)
-
-    def _append_customfield_fields(self):
-        """
-        Append form fields for all CustomFields assigned to this object type.
-        """
-        for customfield in self._get_custom_fields(self._get_content_type()):
-            # Annotate non-required custom fields as nullable
-            if not customfield.required:
-                self.nullable_fields.append(customfield.name)
-
-            self.fields[customfield.name] = self._get_form_field(customfield)
-
-            # Annotate the field in the list of CustomField form fields
-            self.custom_fields[customfield.name] = customfield
-
-
-class CustomFieldModelFilterForm(BootstrapMixin, CustomFieldsMixin, forms.Form):
-    q = forms.CharField(
-        required=False,
-        label='Search'
-    )
-
-    def _get_custom_fields(self, content_type):
-        return CustomField.objects.filter(content_types=content_type).exclude(
-            Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) |
-            Q(type=CustomFieldTypeChoices.TYPE_JSON)
-        )
-
-    def _get_form_field(self, customfield):
-        return customfield.to_form_field(set_initial=False, enforce_required=False)

+ 0 - 17
netbox/extras/forms/models.py

@@ -13,7 +13,6 @@ from utilities.forms import (
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 from virtualization.models import Cluster, ClusterGroup, ClusterType
 
 
 __all__ = (
 __all__ = (
-    'AddRemoveTagsForm',
     'ConfigContextForm',
     'ConfigContextForm',
     'CustomFieldForm',
     'CustomFieldForm',
     'CustomLinkForm',
     'CustomLinkForm',
@@ -134,22 +133,6 @@ class TagForm(BootstrapMixin, forms.ModelForm):
         )
         )
 
 
 
 
-class AddRemoveTagsForm(forms.Form):
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-        # Add add/remove tags fields
-        self.fields['add_tags'] = DynamicModelMultipleChoiceField(
-            queryset=Tag.objects.all(),
-            required=False
-        )
-        self.fields['remove_tags'] = DynamicModelMultipleChoiceField(
-            queryset=Tag.objects.all(),
-            required=False
-        )
-
-
 class ConfigContextForm(BootstrapMixin, forms.ModelForm):
 class ConfigContextForm(BootstrapMixin, forms.ModelForm):
     regions = DynamicModelMultipleChoiceField(
     regions = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),

+ 14 - 14
netbox/ipam/forms/bulk_edit.py

@@ -1,11 +1,11 @@
 from django import forms
 from django import forms
 
 
 from dcim.models import Region, Site, SiteGroup
 from dcim.models import Region, Site, SiteGroup
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
 from ipam.choices import *
 from ipam.choices import *
 from ipam.constants import *
 from ipam.constants import *
 from ipam.models import *
 from ipam.models import *
 from ipam.models import ASN
 from ipam.models import ASN
+from netbox.forms import NetBoxModelBulkEditForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, BulkEditNullBooleanSelect, DatePicker, DynamicModelChoiceField, NumericArrayField, StaticSelect,
     add_blank_choice, BulkEditNullBooleanSelect, DatePicker, DynamicModelChoiceField, NumericArrayField, StaticSelect,
@@ -30,7 +30,7 @@ __all__ = (
 )
 )
 
 
 
 
-class VRFBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VRFBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -55,7 +55,7 @@ class VRFBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class RouteTargetBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RouteTargetBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -75,7 +75,7 @@ class RouteTargetBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class RIRBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RIRBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -93,7 +93,7 @@ class RIRBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['is_private', 'description']
         nullable_fields = ['is_private', 'description']
 
 
 
 
-class ASNBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ASNBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ASN.objects.all(),
         queryset=ASN.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -125,7 +125,7 @@ class ASNBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         }
         }
 
 
 
 
-class AggregateBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class AggregateBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Aggregate.objects.all(),
         queryset=Aggregate.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -156,7 +156,7 @@ class AggregateBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         }
         }
 
 
 
 
-class RoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class RoleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -173,7 +173,7 @@ class RoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class PrefixBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class PrefixBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Prefix.objects.all(),
         queryset=Prefix.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -238,7 +238,7 @@ class PrefixBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class IPRangeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class IPRangeBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=IPRange.objects.all(),
         queryset=IPRange.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -272,7 +272,7 @@ class IPRangeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class IPAddressBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=IPAddress.objects.all(),
         queryset=IPAddress.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -317,7 +317,7 @@ class IPAddressBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class FHRPGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=FHRPGroup.objects.all(),
         queryset=FHRPGroup.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -352,7 +352,7 @@ class FHRPGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['auth_type', 'auth_key', 'description']
         nullable_fields = ['auth_type', 'auth_key', 'description']
 
 
 
 
-class VLANGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -382,7 +382,7 @@ class VLANGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['site', 'description']
         nullable_fields = ['site', 'description']
 
 
 
 
-class VLANBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VLANBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VLAN.objects.all(),
         queryset=VLAN.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -434,7 +434,7 @@ class VLANBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class ServiceTemplateBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ServiceTemplate.objects.all(),
         queryset=ServiceTemplate.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()

+ 15 - 15
netbox/ipam/forms/bulk_import.py

@@ -2,10 +2,10 @@ from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 
 
 from dcim.models import Device, Interface, Site
 from dcim.models import Device, Interface, Site
-from extras.forms import CustomFieldModelCSVForm
 from ipam.choices import *
 from ipam.choices import *
 from ipam.constants import *
 from ipam.constants import *
 from ipam.models import *
 from ipam.models import *
+from netbox.forms import NetBoxModelCSVForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, SlugField
 from utilities.forms import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, SlugField
 from virtualization.models import VirtualMachine, VMInterface
 from virtualization.models import VirtualMachine, VMInterface
@@ -28,7 +28,7 @@ __all__ = (
 )
 )
 
 
 
 
-class VRFCSVForm(CustomFieldModelCSVForm):
+class VRFCSVForm(NetBoxModelCSVForm):
     tenant = CSVModelChoiceField(
     tenant = CSVModelChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         required=False,
         required=False,
@@ -41,7 +41,7 @@ class VRFCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'rd', 'tenant', 'enforce_unique', 'description')
         fields = ('name', 'rd', 'tenant', 'enforce_unique', 'description')
 
 
 
 
-class RouteTargetCSVForm(CustomFieldModelCSVForm):
+class RouteTargetCSVForm(NetBoxModelCSVForm):
     tenant = CSVModelChoiceField(
     tenant = CSVModelChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         required=False,
         required=False,
@@ -54,7 +54,7 @@ class RouteTargetCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'description', 'tenant')
         fields = ('name', 'description', 'tenant')
 
 
 
 
-class RIRCSVForm(CustomFieldModelCSVForm):
+class RIRCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -65,7 +65,7 @@ class RIRCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class AggregateCSVForm(CustomFieldModelCSVForm):
+class AggregateCSVForm(NetBoxModelCSVForm):
     rir = CSVModelChoiceField(
     rir = CSVModelChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -83,7 +83,7 @@ class AggregateCSVForm(CustomFieldModelCSVForm):
         fields = ('prefix', 'rir', 'tenant', 'date_added', 'description')
         fields = ('prefix', 'rir', 'tenant', 'date_added', 'description')
 
 
 
 
-class ASNCSVForm(CustomFieldModelCSVForm):
+class ASNCSVForm(NetBoxModelCSVForm):
     rir = CSVModelChoiceField(
     rir = CSVModelChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -102,7 +102,7 @@ class ASNCSVForm(CustomFieldModelCSVForm):
         help_texts = {}
         help_texts = {}
 
 
 
 
-class RoleCSVForm(CustomFieldModelCSVForm):
+class RoleCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -110,7 +110,7 @@ class RoleCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'weight', 'description')
         fields = ('name', 'slug', 'weight', 'description')
 
 
 
 
-class PrefixCSVForm(CustomFieldModelCSVForm):
+class PrefixCSVForm(NetBoxModelCSVForm):
     vrf = CSVModelChoiceField(
     vrf = CSVModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -174,7 +174,7 @@ class PrefixCSVForm(CustomFieldModelCSVForm):
                 self.fields['vlan'].queryset = self.fields['vlan'].queryset.filter(**params)
                 self.fields['vlan'].queryset = self.fields['vlan'].queryset.filter(**params)
 
 
 
 
-class IPRangeCSVForm(CustomFieldModelCSVForm):
+class IPRangeCSVForm(NetBoxModelCSVForm):
     vrf = CSVModelChoiceField(
     vrf = CSVModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -205,7 +205,7 @@ class IPRangeCSVForm(CustomFieldModelCSVForm):
         )
         )
 
 
 
 
-class IPAddressCSVForm(CustomFieldModelCSVForm):
+class IPAddressCSVForm(NetBoxModelCSVForm):
     vrf = CSVModelChoiceField(
     vrf = CSVModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -312,7 +312,7 @@ class IPAddressCSVForm(CustomFieldModelCSVForm):
         return ipaddress
         return ipaddress
 
 
 
 
-class FHRPGroupCSVForm(CustomFieldModelCSVForm):
+class FHRPGroupCSVForm(NetBoxModelCSVForm):
     protocol = CSVChoiceField(
     protocol = CSVChoiceField(
         choices=FHRPGroupProtocolChoices
         choices=FHRPGroupProtocolChoices
     )
     )
@@ -326,7 +326,7 @@ class FHRPGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'description')
         fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'description')
 
 
 
 
-class VLANGroupCSVForm(CustomFieldModelCSVForm):
+class VLANGroupCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
     scope_type = CSVContentTypeField(
     scope_type = CSVContentTypeField(
         queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
         queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
@@ -354,7 +354,7 @@ class VLANGroupCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class VLANCSVForm(CustomFieldModelCSVForm):
+class VLANCSVForm(NetBoxModelCSVForm):
     site = CSVModelChoiceField(
     site = CSVModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         required=False,
         required=False,
@@ -393,7 +393,7 @@ class VLANCSVForm(CustomFieldModelCSVForm):
         }
         }
 
 
 
 
-class ServiceTemplateCSVForm(CustomFieldModelCSVForm):
+class ServiceTemplateCSVForm(NetBoxModelCSVForm):
     protocol = CSVChoiceField(
     protocol = CSVChoiceField(
         choices=ServiceProtocolChoices,
         choices=ServiceProtocolChoices,
         help_text='IP protocol'
         help_text='IP protocol'
@@ -404,7 +404,7 @@ class ServiceTemplateCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'protocol', 'ports', 'description')
         fields = ('name', 'protocol', 'ports', 'description')
 
 
 
 
-class ServiceCSVForm(CustomFieldModelCSVForm):
+class ServiceCSVForm(NetBoxModelCSVForm):
     device = CSVModelChoiceField(
     device = CSVModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,

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

@@ -2,11 +2,11 @@ from django import forms
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
 from dcim.models import Location, Rack, Region, Site, SiteGroup
 from dcim.models import Location, Rack, Region, Site, SiteGroup
-from extras.forms import CustomFieldModelFilterForm
 from ipam.choices import *
 from ipam.choices import *
 from ipam.constants import *
 from ipam.constants import *
 from ipam.models import *
 from ipam.models import *
 from ipam.models import ASN
 from ipam.models import ASN
+from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.forms import TenancyFilterForm
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple,
     add_blank_choice, DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple,
@@ -39,7 +39,7 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
 ])
 ])
 
 
 
 
-class VRFFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VRF
     model = VRF
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -59,7 +59,7 @@ class VRFFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class RouteTargetFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = RouteTarget
     model = RouteTarget
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -79,7 +79,7 @@ class RouteTargetFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class RIRFilterForm(CustomFieldModelFilterForm):
+class RIRFilterForm(NetBoxModelFilterSetForm):
     model = RIR
     model = RIR
     is_private = forms.NullBooleanField(
     is_private = forms.NullBooleanField(
         required=False,
         required=False,
@@ -91,7 +91,7 @@ class RIRFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class AggregateFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Aggregate
     model = Aggregate
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -112,7 +112,7 @@ class AggregateFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ASNFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = ASN
     model = ASN
     field_groups = [
     field_groups = [
         ['q'],
         ['q'],
@@ -132,12 +132,12 @@ class ASNFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     )
     )
 
 
 
 
-class RoleFilterForm(CustomFieldModelFilterForm):
+class RoleFilterForm(NetBoxModelFilterSetForm):
     model = Role
     model = Role
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class PrefixFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Prefix
     model = Prefix
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -228,7 +228,7 @@ class PrefixFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class IPRangeFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = IPRange
     model = IPRange
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -261,7 +261,7 @@ class IPRangeFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class IPAddressFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = IPAddress
     model = IPAddress
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -321,7 +321,7 @@ class IPAddressFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class FHRPGroupFilterForm(CustomFieldModelFilterForm):
+class FHRPGroupFilterForm(NetBoxModelFilterSetForm):
     model = FHRPGroup
     model = FHRPGroup
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),
@@ -351,7 +351,7 @@ class FHRPGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VLANGroupFilterForm(CustomFieldModelFilterForm):
+class VLANGroupFilterForm(NetBoxModelFilterSetForm):
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
         ['region', 'sitegroup', 'site', 'location', 'rack'],
         ['region', 'sitegroup', 'site', 'location', 'rack'],
@@ -394,7 +394,7 @@ class VLANGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VLANFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VLAN
     model = VLAN
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -448,7 +448,7 @@ class VLANFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ServiceTemplateFilterForm(CustomFieldModelFilterForm):
+class ServiceTemplateFilterForm(NetBoxModelFilterSetForm):
     model = ServiceTemplate
     model = ServiceTemplate
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),

+ 16 - 16
netbox/ipam/forms/models.py

@@ -2,13 +2,13 @@ from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 
 
 from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
 from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
 from ipam.choices import *
 from ipam.choices import *
 from ipam.constants import *
 from ipam.constants import *
 from ipam.formfields import IPNetworkFormField
 from ipam.formfields import IPNetworkFormField
 from ipam.models import *
 from ipam.models import *
 from ipam.models import ASN
 from ipam.models import ASN
+from netbox.forms import NetBoxModelForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from utilities.exceptions import PermissionsViolation
 from utilities.exceptions import PermissionsViolation
 from utilities.forms import (
 from utilities.forms import (
@@ -39,7 +39,7 @@ __all__ = (
 )
 )
 
 
 
 
-class VRFForm(TenancyForm, CustomFieldModelForm):
+class VRFForm(TenancyForm, NetBoxModelForm):
     import_targets = DynamicModelMultipleChoiceField(
     import_targets = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
         required=False
         required=False
@@ -72,7 +72,7 @@ class VRFForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class RouteTargetForm(TenancyForm, CustomFieldModelForm):
+class RouteTargetForm(TenancyForm, NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -89,7 +89,7 @@ class RouteTargetForm(TenancyForm, CustomFieldModelForm):
         )
         )
 
 
 
 
-class RIRForm(CustomFieldModelForm):
+class RIRForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -103,7 +103,7 @@ class RIRForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class AggregateForm(TenancyForm, CustomFieldModelForm):
+class AggregateForm(TenancyForm, NetBoxModelForm):
     rir = DynamicModelChoiceField(
     rir = DynamicModelChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
         label='RIR'
         label='RIR'
@@ -131,7 +131,7 @@ class AggregateForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class ASNForm(TenancyForm, CustomFieldModelForm):
+class ASNForm(TenancyForm, NetBoxModelForm):
     rir = DynamicModelChoiceField(
     rir = DynamicModelChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
         label='RIR',
         label='RIR',
@@ -175,7 +175,7 @@ class ASNForm(TenancyForm, CustomFieldModelForm):
         return instance
         return instance
 
 
 
 
-class RoleForm(CustomFieldModelForm):
+class RoleForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -189,7 +189,7 @@ class RoleForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class PrefixForm(TenancyForm, CustomFieldModelForm):
+class PrefixForm(TenancyForm, NetBoxModelForm):
     vrf = DynamicModelChoiceField(
     vrf = DynamicModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
@@ -264,7 +264,7 @@ class PrefixForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class IPRangeForm(TenancyForm, CustomFieldModelForm):
+class IPRangeForm(TenancyForm, NetBoxModelForm):
     vrf = DynamicModelChoiceField(
     vrf = DynamicModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
@@ -293,7 +293,7 @@ class IPRangeForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class IPAddressForm(TenancyForm, CustomFieldModelForm):
+class IPAddressForm(TenancyForm, NetBoxModelForm):
     device = DynamicModelChoiceField(
     device = DynamicModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
@@ -506,7 +506,7 @@ class IPAddressForm(TenancyForm, CustomFieldModelForm):
         return ipaddress
         return ipaddress
 
 
 
 
-class IPAddressBulkAddForm(TenancyForm, CustomFieldModelForm):
+class IPAddressBulkAddForm(TenancyForm, NetBoxModelForm):
     vrf = DynamicModelChoiceField(
     vrf = DynamicModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
@@ -540,7 +540,7 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
     )
     )
 
 
 
 
-class FHRPGroupForm(CustomFieldModelForm):
+class FHRPGroupForm(NetBoxModelForm):
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False
         required=False
@@ -629,7 +629,7 @@ class FHRPGroupAssignmentForm(BootstrapMixin, forms.ModelForm):
             self.fields['group'].widget.add_query_param('related_ip', ipaddress.pk)
             self.fields['group'].widget.add_query_param('related_ip', ipaddress.pk)
 
 
 
 
-class VLANGroupForm(CustomFieldModelForm):
+class VLANGroupForm(NetBoxModelForm):
     scope_type = ContentTypeChoiceField(
     scope_type = ContentTypeChoiceField(
         queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
         queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
         required=False
         required=False
@@ -736,7 +736,7 @@ class VLANGroupForm(CustomFieldModelForm):
             self.instance.scope_id = None
             self.instance.scope_id = None
 
 
 
 
-class VLANForm(TenancyForm, CustomFieldModelForm):
+class VLANForm(TenancyForm, NetBoxModelForm):
     # VLANGroup assignment fields
     # VLANGroup assignment fields
     scope_type = forms.ChoiceField(
     scope_type = forms.ChoiceField(
         choices=(
         choices=(
@@ -817,7 +817,7 @@ class VLANForm(TenancyForm, CustomFieldModelForm):
         }
         }
 
 
 
 
-class ServiceTemplateForm(CustomFieldModelForm):
+class ServiceTemplateForm(NetBoxModelForm):
     ports = NumericArrayField(
     ports = NumericArrayField(
         base_field=forms.IntegerField(
         base_field=forms.IntegerField(
             min_value=SERVICE_PORT_MIN,
             min_value=SERVICE_PORT_MIN,
@@ -838,7 +838,7 @@ class ServiceTemplateForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class ServiceForm(CustomFieldModelForm):
+class ServiceForm(NetBoxModelForm):
     device = DynamicModelChoiceField(
     device = DynamicModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False
         required=False

+ 1 - 0
netbox/netbox/forms.py → netbox/netbox/forms/__init__.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 
 
 from utilities.forms import BootstrapMixin
 from utilities.forms import BootstrapMixin
+from .base import *
 
 
 OBJ_TYPE_CHOICES = (
 OBJ_TYPE_CHOICES = (
     ('', 'All Objects'),
     ('', 'All Objects'),

+ 108 - 0
netbox/netbox/forms/base.py

@@ -0,0 +1,108 @@
+from django import forms
+from django.contrib.contenttypes.models import ContentType
+from django.db.models import Q
+
+from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices
+from extras.forms.customfields import CustomFieldsMixin
+from extras.models import CustomField, Tag
+from utilities.forms import BootstrapMixin, BulkEditBaseForm, CSVModelForm
+from utilities.forms.fields import DynamicModelMultipleChoiceField
+
+__all__ = (
+    'NetBoxModelForm',
+    'NetBoxModelCSVForm',
+    'NetBoxModelBulkEditForm',
+    'NetBoxModelFilterSetForm',
+)
+
+
+class NetBoxModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm):
+    """
+    Base form for creating & editing NetBox models. Adds support for custom fields.
+    """
+    def _get_content_type(self):
+        return ContentType.objects.get_for_model(self._meta.model)
+
+    def _get_form_field(self, customfield):
+        if self.instance.pk:
+            form_field = customfield.to_form_field(set_initial=False)
+            form_field.initial = self.instance.custom_field_data.get(customfield.name, None)
+            return form_field
+
+        return customfield.to_form_field()
+
+    def clean(self):
+
+        # Save custom field data on instance
+        for cf_name, customfield in self.custom_fields.items():
+            key = cf_name[3:]  # Strip "cf_" from field name
+            value = self.cleaned_data.get(cf_name)
+
+            # Convert "empty" values to null
+            if value in self.fields[cf_name].empty_values:
+                self.instance.custom_field_data[key] = None
+            else:
+                self.instance.custom_field_data[key] = customfield.serialize(value)
+
+        return super().clean()
+
+
+class NetBoxModelCSVForm(CSVModelForm, NetBoxModelForm):
+    """
+    Base form for creating a NetBox objects from CSV data. Used for bulk importing.
+    """
+    def _get_form_field(self, customfield):
+        return customfield.to_form_field(for_csv_import=True)
+
+
+class NetBoxModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditBaseForm):
+    """
+    Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
+    fields and adding/removing tags.
+    """
+    add_tags = DynamicModelMultipleChoiceField(
+        queryset=Tag.objects.all(),
+        required=False
+    )
+    remove_tags = DynamicModelMultipleChoiceField(
+        queryset=Tag.objects.all(),
+        required=False
+    )
+
+    def _get_form_field(self, customfield):
+        return customfield.to_form_field(set_initial=False, enforce_required=False)
+
+    def _append_customfield_fields(self):
+        """
+        Append form fields for all CustomFields assigned to this object type.
+        """
+        for customfield in self._get_custom_fields(self._get_content_type()):
+            # Annotate non-required custom fields as nullable
+            if not customfield.required:
+                self.nullable_fields.append(customfield.name)
+
+            self.fields[customfield.name] = self._get_form_field(customfield)
+
+            # Annotate the field in the list of CustomField form fields
+            self.custom_fields[customfield.name] = customfield
+
+
+class NetBoxModelFilterSetForm(BootstrapMixin, CustomFieldsMixin, forms.Form):
+    """
+    Base form for FilerSet forms. These are used to filter object lists in the NetBox UI.
+
+    The corresponding FilterSet *must* provide a `q` filter.
+    """
+    q = forms.CharField(
+        required=False,
+        label='Search'
+    )
+
+    def _get_custom_fields(self, content_type):
+        return CustomField.objects.filter(content_types=content_type).exclude(
+            Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) |
+            Q(type=CustomFieldTypeChoices.TYPE_JSON)
+        )
+
+    def _get_form_field(self, customfield):
+        return customfield.to_form_field(set_initial=False, enforce_required=False)

+ 6 - 6
netbox/tenancy/forms/bulk_edit.py

@@ -1,6 +1,6 @@
 from django import forms
 from django import forms
 
 
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
+from netbox.forms import NetBoxModelBulkEditForm
 from tenancy.models import *
 from tenancy.models import *
 from utilities.forms import DynamicModelChoiceField
 from utilities.forms import DynamicModelChoiceField
 
 
@@ -17,7 +17,7 @@ __all__ = (
 # Tenants
 # Tenants
 #
 #
 
 
-class TenantGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class TenantGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -35,7 +35,7 @@ class TenantGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['parent', 'description']
         nullable_fields = ['parent', 'description']
 
 
 
 
-class TenantBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class TenantBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -55,7 +55,7 @@ class TenantBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
 # Contacts
 # Contacts
 #
 #
 
 
-class ContactGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ContactGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -73,7 +73,7 @@ class ContactGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['parent', 'description']
         nullable_fields = ['parent', 'description']
 
 
 
 
-class ContactRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ContactRoleBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ContactRole.objects.all(),
         queryset=ContactRole.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -87,7 +87,7 @@ class ContactRoleBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class ContactBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ContactBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Contact.objects.all(),
         queryset=Contact.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()

+ 6 - 6
netbox/tenancy/forms/bulk_import.py

@@ -1,4 +1,4 @@
-from extras.forms import CustomFieldModelCSVForm
+from netbox.forms import NetBoxModelCSVForm
 from tenancy.models import *
 from tenancy.models import *
 from utilities.forms import CSVModelChoiceField, SlugField
 from utilities.forms import CSVModelChoiceField, SlugField
 
 
@@ -15,7 +15,7 @@ __all__ = (
 # Tenants
 # Tenants
 #
 #
 
 
-class TenantGroupCSVForm(CustomFieldModelCSVForm):
+class TenantGroupCSVForm(NetBoxModelCSVForm):
     parent = CSVModelChoiceField(
     parent = CSVModelChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         required=False,
         required=False,
@@ -29,7 +29,7 @@ class TenantGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'parent', 'description')
         fields = ('name', 'slug', 'parent', 'description')
 
 
 
 
-class TenantCSVForm(CustomFieldModelCSVForm):
+class TenantCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
     group = CSVModelChoiceField(
     group = CSVModelChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
@@ -47,7 +47,7 @@ class TenantCSVForm(CustomFieldModelCSVForm):
 # Contacts
 # Contacts
 #
 #
 
 
-class ContactGroupCSVForm(CustomFieldModelCSVForm):
+class ContactGroupCSVForm(NetBoxModelCSVForm):
     parent = CSVModelChoiceField(
     parent = CSVModelChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
         required=False,
         required=False,
@@ -61,7 +61,7 @@ class ContactGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'parent', 'description')
         fields = ('name', 'slug', 'parent', 'description')
 
 
 
 
-class ContactRoleCSVForm(CustomFieldModelCSVForm):
+class ContactRoleCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -69,7 +69,7 @@ class ContactRoleCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'description')
         fields = ('name', 'slug', 'description')
 
 
 
 
-class ContactCSVForm(CustomFieldModelCSVForm):
+class ContactCSVForm(NetBoxModelCSVForm):
     group = CSVModelChoiceField(
     group = CSVModelChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
         required=False,
         required=False,

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

@@ -1,6 +1,6 @@
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
-from extras.forms import CustomFieldModelFilterForm
+from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.models import *
 from tenancy.models import *
 from utilities.forms import DynamicModelMultipleChoiceField, TagFilterField
 from utilities.forms import DynamicModelMultipleChoiceField, TagFilterField
 
 
@@ -17,7 +17,7 @@ __all__ = (
 # Tenants
 # Tenants
 #
 #
 
 
-class TenantGroupFilterForm(CustomFieldModelFilterForm):
+class TenantGroupFilterForm(NetBoxModelFilterSetForm):
     model = TenantGroup
     model = TenantGroup
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
@@ -27,7 +27,7 @@ class TenantGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class TenantFilterForm(CustomFieldModelFilterForm):
+class TenantFilterForm(NetBoxModelFilterSetForm):
     model = Tenant
     model = Tenant
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),
@@ -46,7 +46,7 @@ class TenantFilterForm(CustomFieldModelFilterForm):
 # Contacts
 # Contacts
 #
 #
 
 
-class ContactGroupFilterForm(CustomFieldModelFilterForm):
+class ContactGroupFilterForm(NetBoxModelFilterSetForm):
     model = ContactGroup
     model = ContactGroup
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
@@ -56,12 +56,12 @@ class ContactGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ContactRoleFilterForm(CustomFieldModelFilterForm):
+class ContactRoleFilterForm(NetBoxModelFilterSetForm):
     model = ContactRole
     model = ContactRole
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ContactFilterForm(CustomFieldModelFilterForm):
+class ContactFilterForm(NetBoxModelFilterSetForm):
     model = Contact
     model = Contact
     field_groups = (
     field_groups = (
         ('q', 'tag'),
         ('q', 'tag'),

+ 6 - 6
netbox/tenancy/forms/models.py

@@ -1,7 +1,7 @@
 from django import forms
 from django import forms
 
 
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
+from netbox.forms import NetBoxModelForm
 from tenancy.models import *
 from tenancy.models import *
 from utilities.forms import (
 from utilities.forms import (
     BootstrapMixin, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, SmallTextarea,
     BootstrapMixin, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, SmallTextarea,
@@ -22,7 +22,7 @@ __all__ = (
 # Tenants
 # Tenants
 #
 #
 
 
-class TenantGroupForm(CustomFieldModelForm):
+class TenantGroupForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         required=False
         required=False
@@ -40,7 +40,7 @@ class TenantGroupForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class TenantForm(CustomFieldModelForm):
+class TenantForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     group = DynamicModelChoiceField(
     group = DynamicModelChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
@@ -66,7 +66,7 @@ class TenantForm(CustomFieldModelForm):
 # Contacts
 # Contacts
 #
 #
 
 
-class ContactGroupForm(CustomFieldModelForm):
+class ContactGroupForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
         required=False
         required=False
@@ -82,7 +82,7 @@ class ContactGroupForm(CustomFieldModelForm):
         fields = ('parent', 'name', 'slug', 'description', 'tags')
         fields = ('parent', 'name', 'slug', 'description', 'tags')
 
 
 
 
-class ContactRoleForm(CustomFieldModelForm):
+class ContactRoleForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -94,7 +94,7 @@ class ContactRoleForm(CustomFieldModelForm):
         fields = ('name', 'slug', 'description', 'tags')
         fields = ('name', 'slug', 'description', 'tags')
 
 
 
 
-class ContactForm(CustomFieldModelForm):
+class ContactForm(NetBoxModelForm):
     group = DynamicModelChoiceField(
     group = DynamicModelChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
         required=False
         required=False

+ 6 - 6
netbox/virtualization/forms/bulk_edit.py

@@ -3,8 +3,8 @@ from django import forms
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
 from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
 from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
 from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
 from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
 from ipam.models import VLAN
 from ipam.models import VLAN
+from netbox.forms import NetBoxModelBulkEditForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, BulkEditNullBooleanSelect, BulkRenameForm, CommentField, DynamicModelChoiceField,
     add_blank_choice, BulkEditNullBooleanSelect, BulkRenameForm, CommentField, DynamicModelChoiceField,
@@ -23,7 +23,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ClusterTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ClusterTypeBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -37,7 +37,7 @@ class ClusterTypeBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class ClusterGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ClusterGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -51,7 +51,7 @@ class ClusterGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['description']
         nullable_fields = ['description']
 
 
 
 
-class ClusterBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class ClusterBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -95,7 +95,7 @@ class ClusterBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         ]
         ]
 
 
 
 
-class VirtualMachineBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()
@@ -150,7 +150,7 @@ class VirtualMachineBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm
         ]
         ]
 
 
 
 
-class VMInterfaceBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=VMInterface.objects.all(),
         queryset=VMInterface.objects.all(),
         widget=forms.MultipleHiddenInput()
         widget=forms.MultipleHiddenInput()

+ 6 - 6
netbox/virtualization/forms/bulk_import.py

@@ -1,6 +1,6 @@
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
 from dcim.models import DeviceRole, Platform, Site
 from dcim.models import DeviceRole, Platform, Site
-from extras.forms import CustomFieldModelCSVForm
+from netbox.forms import NetBoxModelCSVForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 from virtualization.choices import *
 from virtualization.choices import *
@@ -15,7 +15,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ClusterTypeCSVForm(CustomFieldModelCSVForm):
+class ClusterTypeCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -23,7 +23,7 @@ class ClusterTypeCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'description')
         fields = ('name', 'slug', 'description')
 
 
 
 
-class ClusterGroupCSVForm(CustomFieldModelCSVForm):
+class ClusterGroupCSVForm(NetBoxModelCSVForm):
     slug = SlugField()
     slug = SlugField()
 
 
     class Meta:
     class Meta:
@@ -31,7 +31,7 @@ class ClusterGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'description')
         fields = ('name', 'slug', 'description')
 
 
 
 
-class ClusterCSVForm(CustomFieldModelCSVForm):
+class ClusterCSVForm(NetBoxModelCSVForm):
     type = CSVModelChoiceField(
     type = CSVModelChoiceField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
         to_field_name='name',
         to_field_name='name',
@@ -61,7 +61,7 @@ class ClusterCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'type', 'group', 'site', 'comments')
         fields = ('name', 'type', 'group', 'site', 'comments')
 
 
 
 
-class VirtualMachineCSVForm(CustomFieldModelCSVForm):
+class VirtualMachineCSVForm(NetBoxModelCSVForm):
     status = CSVChoiceField(
     status = CSVChoiceField(
         choices=VirtualMachineStatusChoices,
         choices=VirtualMachineStatusChoices,
         help_text='Operational status of device'
         help_text='Operational status of device'
@@ -99,7 +99,7 @@ class VirtualMachineCSVForm(CustomFieldModelCSVForm):
         )
         )
 
 
 
 
-class VMInterfaceCSVForm(CustomFieldModelCSVForm):
+class VMInterfaceCSVForm(NetBoxModelCSVForm):
     virtual_machine = CSVModelChoiceField(
     virtual_machine = CSVModelChoiceField(
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
         to_field_name='name'
         to_field_name='name'

+ 7 - 6
netbox/virtualization/forms/filtersets.py

@@ -2,7 +2,8 @@ from django import forms
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
 from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
 from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
-from extras.forms import CustomFieldModelFilterForm, LocalConfigContextFilterForm
+from extras.forms import LocalConfigContextFilterForm
+from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.forms import TenancyFilterForm
 from tenancy.forms import TenancyFilterForm
 from utilities.forms import (
 from utilities.forms import (
     DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
     DynamicModelMultipleChoiceField, StaticSelect, StaticSelectMultiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
@@ -19,17 +20,17 @@ __all__ = (
 )
 )
 
 
 
 
-class ClusterTypeFilterForm(CustomFieldModelFilterForm):
+class ClusterTypeFilterForm(NetBoxModelFilterSetForm):
     model = ClusterType
     model = ClusterType
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ClusterGroupFilterForm(CustomFieldModelFilterForm):
+class ClusterGroupFilterForm(NetBoxModelFilterSetForm):
     model = ClusterGroup
     model = ClusterGroup
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class ClusterFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
+class ClusterFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
     model = Cluster
     model = Cluster
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -71,7 +72,7 @@ class ClusterFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VirtualMachineFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldModelFilterForm):
+class VirtualMachineFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
     model = VirtualMachine
     model = VirtualMachine
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],
@@ -151,7 +152,7 @@ class VirtualMachineFilterForm(LocalConfigContextFilterForm, TenancyFilterForm,
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VMInterfaceFilterForm(CustomFieldModelFilterForm):
+class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
     model = VMInterface
     model = VMInterface
     field_groups = [
     field_groups = [
         ['q', 'tag'],
         ['q', 'tag'],

+ 6 - 6
netbox/virtualization/forms/models.py

@@ -5,9 +5,9 @@ from django.core.exceptions import ValidationError
 from dcim.forms.common import InterfaceCommonForm
 from dcim.forms.common import InterfaceCommonForm
 from dcim.forms.models import INTERFACE_MODE_HELP_TEXT
 from dcim.forms.models import INTERFACE_MODE_HELP_TEXT
 from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup
 from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
 from ipam.models import IPAddress, VLAN, VLANGroup
 from ipam.models import IPAddress, VLAN, VLANGroup
+from netbox.forms import NetBoxModelForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from utilities.forms import (
 from utilities.forms import (
     BootstrapMixin, CommentField, ConfirmationForm, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
     BootstrapMixin, CommentField, ConfirmationForm, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
@@ -26,7 +26,7 @@ __all__ = (
 )
 )
 
 
 
 
-class ClusterTypeForm(CustomFieldModelForm):
+class ClusterTypeForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -40,7 +40,7 @@ class ClusterTypeForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class ClusterGroupForm(CustomFieldModelForm):
+class ClusterGroupForm(NetBoxModelForm):
     slug = SlugField()
     slug = SlugField()
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
@@ -54,7 +54,7 @@ class ClusterGroupForm(CustomFieldModelForm):
         )
         )
 
 
 
 
-class ClusterForm(TenancyForm, CustomFieldModelForm):
+class ClusterForm(TenancyForm, NetBoxModelForm):
     type = DynamicModelChoiceField(
     type = DynamicModelChoiceField(
         queryset=ClusterType.objects.all()
         queryset=ClusterType.objects.all()
     )
     )
@@ -171,7 +171,7 @@ class ClusterRemoveDevicesForm(ConfirmationForm):
     )
     )
 
 
 
 
-class VirtualMachineForm(TenancyForm, CustomFieldModelForm):
+class VirtualMachineForm(TenancyForm, NetBoxModelForm):
     cluster_group = DynamicModelChoiceField(
     cluster_group = DynamicModelChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         required=False,
         required=False,
@@ -271,7 +271,7 @@ class VirtualMachineForm(TenancyForm, CustomFieldModelForm):
             self.fields['primary_ip6'].widget.attrs['readonly'] = True
             self.fields['primary_ip6'].widget.attrs['readonly'] = True
 
 
 
 
-class VMInterfaceForm(InterfaceCommonForm, CustomFieldModelForm):
+class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=VMInterface.objects.all(),
         queryset=VMInterface.objects.all(),
         required=False,
         required=False,

+ 4 - 4
netbox/wireless/forms/bulk_edit.py

@@ -1,8 +1,8 @@
 from django import forms
 from django import forms
 
 
 from dcim.choices import LinkStatusChoices
 from dcim.choices import LinkStatusChoices
-from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
 from ipam.models import VLAN
 from ipam.models import VLAN
+from netbox.forms import NetBoxModelBulkEditForm
 from utilities.forms import add_blank_choice, DynamicModelChoiceField
 from utilities.forms import add_blank_choice, DynamicModelChoiceField
 from wireless.choices import *
 from wireless.choices import *
 from wireless.constants import SSID_MAX_LENGTH
 from wireless.constants import SSID_MAX_LENGTH
@@ -15,7 +15,7 @@ __all__ = (
 )
 )
 
 
 
 
-class WirelessLANGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class WirelessLANGroupBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -33,7 +33,7 @@ class WirelessLANGroupBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditFo
         nullable_fields = ['parent', 'description']
         nullable_fields = ['parent', 'description']
 
 
 
 
-class WirelessLANBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class WirelessLANBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=WirelessLAN.objects.all(),
         queryset=WirelessLAN.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput
@@ -72,7 +72,7 @@ class WirelessLANBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
         nullable_fields = ['ssid', 'group', 'vlan', 'description', 'auth_type', 'auth_cipher', 'auth_psk']
         nullable_fields = ['ssid', 'group', 'vlan', 'description', 'auth_type', 'auth_cipher', 'auth_psk']
 
 
 
 
-class WirelessLinkBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm):
+class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=WirelessLink.objects.all(),
         queryset=WirelessLink.objects.all(),
         widget=forms.MultipleHiddenInput
         widget=forms.MultipleHiddenInput

+ 4 - 4
netbox/wireless/forms/bulk_import.py

@@ -1,7 +1,7 @@
 from dcim.choices import LinkStatusChoices
 from dcim.choices import LinkStatusChoices
 from dcim.models import Interface
 from dcim.models import Interface
-from extras.forms import CustomFieldModelCSVForm
 from ipam.models import VLAN
 from ipam.models import VLAN
+from netbox.forms import NetBoxModelCSVForm
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
 from wireless.choices import *
 from wireless.choices import *
 from wireless.models import *
 from wireless.models import *
@@ -13,7 +13,7 @@ __all__ = (
 )
 )
 
 
 
 
-class WirelessLANGroupCSVForm(CustomFieldModelCSVForm):
+class WirelessLANGroupCSVForm(NetBoxModelCSVForm):
     parent = CSVModelChoiceField(
     parent = CSVModelChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
         required=False,
         required=False,
@@ -27,7 +27,7 @@ class WirelessLANGroupCSVForm(CustomFieldModelCSVForm):
         fields = ('name', 'slug', 'parent', 'description')
         fields = ('name', 'slug', 'parent', 'description')
 
 
 
 
-class WirelessLANCSVForm(CustomFieldModelCSVForm):
+class WirelessLANCSVForm(NetBoxModelCSVForm):
     group = CSVModelChoiceField(
     group = CSVModelChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
         required=False,
         required=False,
@@ -56,7 +56,7 @@ class WirelessLANCSVForm(CustomFieldModelCSVForm):
         fields = ('ssid', 'group', 'description', 'vlan', 'auth_type', 'auth_cipher', 'auth_psk')
         fields = ('ssid', 'group', 'description', 'vlan', 'auth_type', 'auth_cipher', 'auth_psk')
 
 
 
 
-class WirelessLinkCSVForm(CustomFieldModelCSVForm):
+class WirelessLinkCSVForm(NetBoxModelCSVForm):
     status = CSVChoiceField(
     status = CSVChoiceField(
         choices=LinkStatusChoices,
         choices=LinkStatusChoices,
         help_text='Connection status'
         help_text='Connection status'

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

@@ -2,7 +2,7 @@ from django import forms
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
 from dcim.choices import LinkStatusChoices
 from dcim.choices import LinkStatusChoices
-from extras.forms import CustomFieldModelFilterForm
+from netbox.forms import NetBoxModelFilterSetForm
 from utilities.forms import add_blank_choice, DynamicModelMultipleChoiceField, StaticSelect, TagFilterField
 from utilities.forms import add_blank_choice, DynamicModelMultipleChoiceField, StaticSelect, TagFilterField
 from wireless.choices import *
 from wireless.choices import *
 from wireless.models import *
 from wireless.models import *
@@ -14,7 +14,7 @@ __all__ = (
 )
 )
 
 
 
 
-class WirelessLANGroupFilterForm(CustomFieldModelFilterForm):
+class WirelessLANGroupFilterForm(NetBoxModelFilterSetForm):
     model = WirelessLANGroup
     model = WirelessLANGroup
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
@@ -24,7 +24,7 @@ class WirelessLANGroupFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class WirelessLANFilterForm(CustomFieldModelFilterForm):
+class WirelessLANFilterForm(NetBoxModelFilterSetForm):
     model = WirelessLAN
     model = WirelessLAN
     field_groups = [
     field_groups = [
         ('q', 'tag'),
         ('q', 'tag'),
@@ -56,7 +56,7 @@ class WirelessLANFilterForm(CustomFieldModelFilterForm):
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class WirelessLinkFilterForm(CustomFieldModelFilterForm):
+class WirelessLinkFilterForm(NetBoxModelFilterSetForm):
     model = WirelessLink
     model = WirelessLink
     ssid = forms.CharField(
     ssid = forms.CharField(
         required=False,
         required=False,

+ 4 - 4
netbox/wireless/forms/models.py

@@ -1,7 +1,7 @@
 from dcim.models import Device, Interface, Location, Site
 from dcim.models import Device, Interface, Location, Site
-from extras.forms import CustomFieldModelForm
 from extras.models import Tag
 from extras.models import Tag
 from ipam.models import VLAN
 from ipam.models import VLAN
+from netbox.forms import NetBoxModelForm
 from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, StaticSelect
 from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, StaticSelect
 from wireless.models import *
 from wireless.models import *
 
 
@@ -12,7 +12,7 @@ __all__ = (
 )
 )
 
 
 
 
-class WirelessLANGroupForm(CustomFieldModelForm):
+class WirelessLANGroupForm(NetBoxModelForm):
     parent = DynamicModelChoiceField(
     parent = DynamicModelChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
         required=False
         required=False
@@ -30,7 +30,7 @@ class WirelessLANGroupForm(CustomFieldModelForm):
         ]
         ]
 
 
 
 
-class WirelessLANForm(CustomFieldModelForm):
+class WirelessLANForm(NetBoxModelForm):
     group = DynamicModelChoiceField(
     group = DynamicModelChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
         required=False
         required=False
@@ -61,7 +61,7 @@ class WirelessLANForm(CustomFieldModelForm):
         }
         }
 
 
 
 
-class WirelessLinkForm(CustomFieldModelForm):
+class WirelessLinkForm(NetBoxModelForm):
     site_a = DynamicModelChoiceField(
     site_a = DynamicModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         required=False,
         required=False,