Closes #8667: Support position patterning when creating module bays & templates

This commit is contained in:
jeremystretch 2022-02-23 13:02:14 -05:00
parent 6604ebfd01
commit a2fe23549b
5 changed files with 51 additions and 21 deletions

View File

@ -8,11 +8,13 @@ from utilities.forms import (
)
__all__ = (
'ModularComponentTemplateCreateForm',
'DeviceComponentCreateForm',
'ComponentTemplateCreateForm',
'DeviceComponentCreateForm',
'FrontPortCreateForm',
'FrontPortTemplateCreateForm',
'ModularComponentTemplateCreateForm',
'ModuleBayCreateForm',
'ModuleBayTemplateCreateForm',
'VirtualChassisCreateForm',
)
@ -34,14 +36,17 @@ class ComponentCreateForm(BootstrapMixin, forms.Form):
def clean(self):
super().clean()
# Validate that the number of components being created from both the name_pattern and label_pattern are equal
if self.cleaned_data['label_pattern']:
name_pattern_count = len(self.cleaned_data['name_pattern'])
label_pattern_count = len(self.cleaned_data['label_pattern'])
if name_pattern_count != label_pattern_count:
# Validate that all patterned fields generate an equal number of values
patterned_fields = [
field_name for field_name in self.fields if field_name.endswith('_pattern')
]
pattern_count = len(self.cleaned_data['name_pattern'])
for field_name in patterned_fields:
value_count = len(self.cleaned_data[field_name])
if self.cleaned_data[field_name] and value_count != pattern_count:
raise forms.ValidationError({
'label_pattern': f'The provided name pattern will create {name_pattern_count} components, however '
f'{label_pattern_count} labels will be generated. These counts must match.'
field_name: f'The provided pattern specifies {value_count} values, but {pattern_count} are '
f'expected.'
}, code='label_pattern_mismatch')
@ -176,6 +181,24 @@ class FrontPortCreateForm(DeviceComponentCreateForm):
}
class ModuleBayTemplateCreateForm(ComponentTemplateCreateForm):
position_pattern = ExpandableNameField(
label='Position',
required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
)
field_order = ('device_type', 'name_pattern', 'label_pattern', 'position_pattern')
class ModuleBayCreateForm(DeviceComponentCreateForm):
position_pattern = ExpandableNameField(
label='Position',
required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
)
field_order = ('device', 'name_pattern', 'label_pattern', 'position_pattern')
class VirtualChassisCreateForm(NetBoxModelForm):
region = DynamicModelChoiceField(
queryset=Region.objects.all(),

View File

@ -744,8 +744,8 @@ class DeviceModuleBayTable(ModuleBayTable):
class Meta(DeviceComponentTable.Meta):
model = ModuleBay
fields = ('pk', 'id', 'name', 'label', 'description', 'installed_module', 'tags', 'actions')
default_columns = ('pk', 'name', 'label', 'description', 'installed_module')
fields = ('pk', 'id', 'name', 'label', 'position', 'installed_module', 'description', 'tags', 'actions')
default_columns = ('pk', 'name', 'label', 'installed_module', 'description')
class InventoryItemTable(DeviceComponentTable):

View File

@ -1324,9 +1324,10 @@ class RearPortTemplateBulkDeleteView(generic.BulkDeleteView):
class ModuleBayTemplateCreateView(generic.ComponentCreateView):
queryset = ModuleBayTemplate.objects.all()
form = forms.ComponentTemplateCreateForm
form = forms.ModuleBayTemplateCreateForm
model_form = forms.ModuleBayTemplateForm
template_name = 'dcim/component_template_create.html'
template_name = 'dcim/modulebaytemplate_create.html'
patterned_fields = ('name', 'label', 'position')
class ModuleBayTemplateEditView(generic.ObjectEditView):
@ -2304,8 +2305,9 @@ class ModuleBayView(generic.ObjectView):
class ModuleBayCreateView(generic.ComponentCreateView):
queryset = ModuleBay.objects.all()
form = forms.DeviceComponentCreateForm
form = forms.ModuleBayCreateForm
model_form = forms.ModuleBayForm
patterned_fields = ('name', 'label', 'position')
class ModuleBayEditView(generic.ObjectEditView):

View File

@ -587,14 +587,12 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
if form.is_valid():
new_components = []
data = deepcopy(request.POST)
names = form.cleaned_data['name_pattern']
labels = form.cleaned_data.get('label_pattern')
pattern_count = len(form.cleaned_data[f'{self.patterned_fields[0]}_pattern'])
for i, name in enumerate(names):
label = labels[i] if labels else None
# Initialize the individual component form
data['name'] = name
data['label'] = label
for i in range(pattern_count):
for field_name in self.patterned_fields:
if form.cleaned_data.get(f'{field_name}_pattern'):
data[field_name] = form.cleaned_data[f'{field_name}_pattern'][i]
if hasattr(form, 'get_iterative_data'):
data.update(form.get_iterative_data(i))

View File

@ -0,0 +1,7 @@
{% extends 'dcim/component_template_create.html' %}
{% load form_helpers %}
{% block replication_fields %}
{{ block.super }}
{% render_field replication_form.position_pattern %}
{% endblock replication_fields %}