Browse Source

Add custom field support to ComponentCreateForm

Jeremy Stretch 5 years ago
parent
commit
9db492eb07
2 changed files with 46 additions and 14 deletions
  1. 18 11
      netbox/dcim/forms.py
  2. 28 3
      netbox/extras/forms.py

+ 18 - 11
netbox/dcim/forms.py

@@ -12,8 +12,8 @@ from timezone_field import TimeZoneFormField
 
 
 from circuits.models import Circuit, CircuitTermination, Provider
 from circuits.models import Circuit, CircuitTermination, Provider
 from extras.forms import (
 from extras.forms import (
-    AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldModelCSVForm, CustomFieldFilterForm, CustomFieldModelForm,
-    LocalConfigContextFilterForm,
+    AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldModelCSVForm, CustomFieldFilterForm,
+    CustomFieldModelForm, LocalConfigContextFilterForm,
 )
 )
 from extras.models import Tag
 from extras.models import Tag
 from ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
 from ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
@@ -22,10 +22,9 @@ from tenancy.forms import TenancyFilterForm, TenancyForm
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import (
 from utilities.forms import (
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
-    ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelForm,
-    DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField,
-    NumericArrayField, SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField,
-    BOOLEAN_WITH_BLANK_CHOICES,
+    ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, DynamicModelChoiceField,
+    DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField, NumericArrayField, SelectWithPK,
+    SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
 )
 )
 from virtualization.models import Cluster, ClusterGroup
 from virtualization.models import Cluster, ClusterGroup
 from .choices import *
 from .choices import *
@@ -119,7 +118,7 @@ class InterfaceCommonForm(forms.Form):
                 })
                 })
 
 
 
 
-class ComponentForm(BootstrapMixin, forms.Form):
+class ComponentForm(forms.Form):
     """
     """
     Subclass this form when facilitating the creation of one or more device component or component templates based on
     Subclass this form when facilitating the creation of one or more device component or component templates based on
     a name pattern.
     a name pattern.
@@ -1073,7 +1072,7 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
 # Device component templates
 # Device component templates
 #
 #
 
 
-class ComponentTemplateCreateForm(ComponentForm):
+class ComponentTemplateCreateForm(BootstrapMixin, ComponentForm):
     """
     """
     Base form for the creation of device component templates (subclassed from ComponentTemplateModel).
     Base form for the creation of device component templates (subclassed from ComponentTemplateModel).
     """
     """
@@ -2270,11 +2269,10 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
 # Device components
 # Device components
 #
 #
 
 
-class ComponentCreateForm(ComponentForm):
+class ComponentCreateForm(BootstrapMixin, CustomFieldForm, ComponentForm):
     """
     """
     Base form for the creation of device components (models subclassed from ComponentModel).
     Base form for the creation of device components (models subclassed from ComponentModel).
     """
     """
-    # TODO: Enable custom field support
     device = DynamicModelChoiceField(
     device = DynamicModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         display_field='display_name'
         display_field='display_name'
@@ -2289,7 +2287,7 @@ class ComponentCreateForm(ComponentForm):
     )
     )
 
 
 
 
-class DeviceBulkAddComponentForm(ComponentForm):
+class DeviceBulkAddComponentForm(BootstrapMixin, ComponentForm):
     # TODO: Enable custom field support
     # TODO: Enable custom field support
     pk = forms.ModelMultipleChoiceField(
     pk = forms.ModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
@@ -2337,6 +2335,7 @@ class ConsolePortForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class ConsolePortCreateForm(ComponentCreateForm):
 class ConsolePortCreateForm(ComponentCreateForm):
+    model = ConsolePort
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=add_blank_choice(ConsolePortTypeChoices),
         choices=add_blank_choice(ConsolePortTypeChoices),
         required=False,
         required=False,
@@ -2415,6 +2414,7 @@ class ConsoleServerPortForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class ConsoleServerPortCreateForm(ComponentCreateForm):
 class ConsoleServerPortCreateForm(ComponentCreateForm):
+    model = ConsoleServerPort
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=add_blank_choice(ConsolePortTypeChoices),
         choices=add_blank_choice(ConsolePortTypeChoices),
         required=False,
         required=False,
@@ -2493,6 +2493,7 @@ class PowerPortForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class PowerPortCreateForm(ComponentCreateForm):
 class PowerPortCreateForm(ComponentCreateForm):
+    model = PowerPort
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=add_blank_choice(PowerPortTypeChoices),
         choices=add_blank_choice(PowerPortTypeChoices),
         required=False,
         required=False,
@@ -2596,6 +2597,7 @@ class PowerOutletForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class PowerOutletCreateForm(ComponentCreateForm):
 class PowerOutletCreateForm(ComponentCreateForm):
+    model = PowerOutlet
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=add_blank_choice(PowerOutletTypeChoices),
         choices=add_blank_choice(PowerOutletTypeChoices),
         required=False,
         required=False,
@@ -2808,6 +2810,7 @@ class InterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
 
 
 
 
 class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
 class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
+    model = Interface
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=InterfaceTypeChoices,
         choices=InterfaceTypeChoices,
         widget=StaticSelect2(),
         widget=StaticSelect2(),
@@ -3089,6 +3092,7 @@ class FrontPortForm(BootstrapMixin, CustomFieldModelForm):
 
 
 # TODO: Merge with FrontPortTemplateCreateForm to remove duplicate logic
 # TODO: Merge with FrontPortTemplateCreateForm to remove duplicate logic
 class FrontPortCreateForm(ComponentCreateForm):
 class FrontPortCreateForm(ComponentCreateForm):
+    model = FrontPort
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=PortTypeChoices,
         choices=PortTypeChoices,
         widget=StaticSelect2(),
         widget=StaticSelect2(),
@@ -3247,6 +3251,7 @@ class RearPortForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class RearPortCreateForm(ComponentCreateForm):
 class RearPortCreateForm(ComponentCreateForm):
+    model = RearPort
     type = forms.ChoiceField(
     type = forms.ChoiceField(
         choices=PortTypeChoices,
         choices=PortTypeChoices,
         widget=StaticSelect2(),
         widget=StaticSelect2(),
@@ -3326,6 +3331,7 @@ class DeviceBayForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class DeviceBayCreateForm(ComponentCreateForm):
 class DeviceBayCreateForm(ComponentCreateForm):
+    model = DeviceBay
     field_order = ('device', 'name_pattern', 'label_pattern', 'description', 'tags')
     field_order = ('device', 'name_pattern', 'label_pattern', 'description', 'tags')
 
 
 
 
@@ -3449,6 +3455,7 @@ class InventoryItemForm(BootstrapMixin, CustomFieldModelForm):
 
 
 
 
 class InventoryItemCreateForm(ComponentCreateForm):
 class InventoryItemCreateForm(ComponentCreateForm):
+    model = InventoryItem
     manufacturer = DynamicModelChoiceField(
     manufacturer = DynamicModelChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
         required=False
         required=False

+ 28 - 3
netbox/extras/forms.py

@@ -7,8 +7,8 @@ from dcim.models import DeviceRole, Platform, Region, Site
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect,
     add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect,
-    ContentTypeSelect, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField,
-    StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES,
+    CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2,
+    BOOLEAN_WITH_BLANK_CHOICES,
 )
 )
 from virtualization.models import Cluster, ClusterGroup
 from virtualization.models import Cluster, ClusterGroup
 from .choices import *
 from .choices import *
@@ -19,8 +19,33 @@ from .models import ConfigContext, CustomField, ImageAttachment, ObjectChange, T
 # Custom fields
 # Custom fields
 #
 #
 
 
-class CustomFieldModelForm(forms.ModelForm):
+class CustomFieldForm(forms.Form):
+    """
+    Extend Form to include custom field support.
+    """
+    model = None
+
+    def __init__(self, *args, **kwargs):
+        if self.model is None:
+            raise NotImplementedError("CustomFieldForm must specify a model class.")
+        self.custom_fields = []
 
 
+        super().__init__(*args, **kwargs)
+
+        # Append relevant custom fields to the form instance
+        obj_type = ContentType.objects.get_for_model(self.model)
+        for cf in CustomField.objects.filter(content_types=obj_type):
+            field_name = 'cf_{}'.format(cf.name)
+            self.fields[field_name] = cf.to_form_field()
+
+            # Annotate the field in the list of CustomField form fields
+            self.custom_fields.append(field_name)
+
+
+class CustomFieldModelForm(forms.ModelForm):
+    """
+    Extend ModelForm to include custom field support.
+    """
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
 
 
         self.obj_type = ContentType.objects.get_for_model(self._meta.model)
         self.obj_type = ContentType.objects.get_for_model(self._meta.model)