diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 82e489fa8..b4db64d81 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -180,6 +180,18 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm): required=False, label='Site', widget=forms.Select( + attrs={'filter-for': 'vlan_group', 'nullable': 'true'} + ) + ) + vlan_group = ChainedModelChoiceField( + queryset=VLANGroup.objects.all(), + chains=( + ('site', 'site'), + ), + required=False, + label='VLAN group', + widget=APISelect( + api_url='/api/ipam/vlan-groups/?site_id={{site}}', attrs={'filter-for': 'vlan', 'nullable': 'true'} ) ) @@ -187,11 +199,12 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm): queryset=VLAN.objects.all(), chains=( ('site', 'site'), + ('group', 'vlan_group'), ), required=False, label='VLAN', widget=APISelect( - api_url='/api/ipam/vlans/?site_id={{site}}', display_field='display_name' + api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}', display_field='display_name' ) ) @@ -200,6 +213,14 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm): fields = ['prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant'] def __init__(self, *args, **kwargs): + + # Initialize helper selectors + instance = kwargs.get('instance') + initial = kwargs.get('initial', {}) + if instance and instance.vlan is not None: + initial['vlan_group'] = instance.vlan.group + kwargs['initial'] = initial + super(PrefixForm, self).__init__(*args, **kwargs) self.fields['vrf'].empty_label = 'Global' diff --git a/netbox/templates/ipam/prefix_edit.html b/netbox/templates/ipam/prefix_edit.html index 089335c02..938a75da3 100644 --- a/netbox/templates/ipam/prefix_edit.html +++ b/netbox/templates/ipam/prefix_edit.html @@ -8,13 +8,19 @@ {% render_field form.prefix %} {% render_field form.status %} {% render_field form.vrf %} - {% render_field form.site %} - {% render_field form.vlan %} {% render_field form.role %} {% render_field form.description %} {% render_field form.is_pool %} +
+
Site/VLAN Assignment
+
+ {% render_field form.site %} + {% render_field form.vlan_group %} + {% render_field form.vlan %} +
+
Tenancy
diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index 231de52e5..16c40a727 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -478,8 +478,8 @@ class ChainedFieldsMixin(forms.BaseForm): filters_dict = {} for (db_field, parent_field) in field.chains: - if self.is_bound and self.data.get(parent_field): - filters_dict[db_field] = self.data[parent_field] + if self.is_bound and parent_field in self.data: + filters_dict[db_field] = self.data[parent_field] or None elif self.initial.get(parent_field): filters_dict[db_field] = self.initial[parent_field] elif self.fields[parent_field].widget.attrs.get('nullable'):