Add custom field support to ComponentCreateForm

This commit is contained in:
Jeremy Stretch 2021-03-01 13:37:53 -05:00
parent d6ee4d58ba
commit 9db492eb07
2 changed files with 46 additions and 14 deletions

View File

@ -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, AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldForm, CustomFieldModelCSVForm, CustomFieldFilterForm,
LocalConfigContextFilterForm, 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, ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, DynamicModelChoiceField,
DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model, JSONField, NumericArrayField, SelectWithPK,
NumericArrayField, SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
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

View File

@ -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, CSVModelForm, DateTimePicker, DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect2,
StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES, 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)