Fix FrontPortCreateForm

This commit is contained in:
Jeremy Stretch
2025-11-18 11:21:29 -05:00
parent 4790dbba96
commit a7c3971a43
3 changed files with 17 additions and 47 deletions

View File

@@ -1617,6 +1617,7 @@ class FrontPortForm(ModularDeviceComponentForm):
]
def clean(self):
super().clean()
# Count of selected rear port & position pairs much match the assigned number of positions
if len(self.cleaned_data['rear_ports']) != self.cleaned_data['positions']:
@@ -1652,7 +1653,7 @@ class FrontPortForm(ModularDeviceComponentForm):
"""
occupied_rear_port_positions = [
f'{assignment.rear_port_id}:{assignment.rear_port_position}'
for assignment in PortAssignment.objects.filter(front_port__device=device).exclude(front_port=front_port)
for assignment in PortAssignment.objects.filter(front_port__device=device).exclude(front_port=front_port.pk)
]
choices = []

View File

@@ -269,58 +269,30 @@ class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm):
}
)
)
rear_port = forms.MultipleChoiceField(
choices=[],
label=_('Rear ports'),
help_text=_('Select one rear port assignment for each front port being created.'),
widget=forms.SelectMultiple(attrs={'size': 6})
)
# Override fieldsets from FrontPortForm to omit rear_port_position
fieldsets = (
FieldSet(
'device', 'module', 'name', 'label', 'type', 'color', 'rear_port', 'mark_connected', 'description', 'tags',
'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'rear_ports', 'mark_connected',
'description', 'tags',
),
)
class Meta(model_forms.FrontPortForm.Meta):
exclude = ('name', 'label', 'positions')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if device_id := self.data.get('device') or self.initial.get('device'):
device = Device.objects.get(pk=device_id)
else:
return
# Determine which rear port positions are occupied. These will be excluded from the list of available
# mappings.
occupied_port_positions = [
(front_port.rear_port_id, front_port.rear_port_position)
for front_port in device.frontports.all()
class Meta:
model = FrontPort
fields = [
'device', 'module', 'type', 'color', 'positions', 'mark_connected', 'description', 'owner', 'tags',
]
# Populate rear port choices
choices = []
rear_ports = RearPort.objects.filter(device=device)
for rear_port in rear_ports:
for i in range(1, rear_port.positions + 1):
if (rear_port.pk, i) not in occupied_port_positions:
choices.append(
('{}:{}'.format(rear_port.pk, i), '{}:{}'.format(rear_port.name, i))
)
self.fields['rear_port'].choices = choices
def clean(self):
super().clean()
super(NetBoxModelForm, self).clean()
# Check that the number of FrontPorts to be created matches the selected number of RearPort positions
frontport_count = len(self.cleaned_data['name'])
rearport_count = len(self.cleaned_data['rear_port'])
rearport_count = len(self.cleaned_data['rear_ports'])
if frontport_count != rearport_count:
raise forms.ValidationError({
'rear_port': _(
'rear_ports': _(
"The number of front ports to be created ({frontport_count}) must match the selected number of "
"rear port positions ({rearport_count})."
).format(
@@ -330,13 +302,10 @@ class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm):
})
def get_iterative_data(self, iteration):
# Assign rear port and position from selected set
rear_port, position = self.cleaned_data['rear_port'][iteration].split(':')
positions = self.cleaned_data['positions']
offset = positions * iteration
return {
'rear_port': int(rear_port),
'rear_port_position': int(position),
'rear_ports': self.cleaned_data['rear_ports'][offset:offset + positions]
}

View File

@@ -1,6 +1,5 @@
import logging
from collections import defaultdict
from copy import deepcopy
from django.contrib import messages
from django.db import router, transaction
@@ -563,7 +562,7 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
if form.is_valid():
new_components = []
data = deepcopy(request.POST)
data = request.POST.copy()
pattern_count = len(form.cleaned_data[self.form.replication_fields[0]])
for i in range(pattern_count):
@@ -572,7 +571,8 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
data[field_name] = form.cleaned_data[field_name][i]
if hasattr(form, 'get_iterative_data'):
data.update(form.get_iterative_data(i))
for k, v in form.get_iterative_data(i).items():
data.setlist(k, v)
component_form = self.model_form(data)