99from dcim .constants import *
1010from dcim .models import *
1111from extras .models import ConfigTemplate
12- from ipam .models import VRF , IPAddress
12+ from ipam .choices import VLANQinQRoleChoices
13+ from ipam .models import VLAN , VRF , IPAddress , VLANGroup
1314from netbox .choices import *
1415from netbox .forms import NetBoxModelImportForm
1516from tenancy .models import Tenant
1617from utilities .forms .fields import (
1718 CSVChoiceField , CSVContentTypeField , CSVModelChoiceField , CSVModelMultipleChoiceField , CSVTypedChoiceField ,
1819 SlugField ,
1920)
20- from virtualization .models import Cluster , VMInterface , VirtualMachine
21+ from virtualization .models import Cluster , VirtualMachine , VMInterface
2122from wireless .choices import WirelessRoleChoices
2223from .common import ModuleCommonForm
2324
@@ -938,7 +939,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
938939 required = False ,
939940 to_field_name = 'name' ,
940941 help_text = mark_safe (
941- _ ('VDC names separated by commas, encased with double quotes. Example:' ) + ' <code>vdc1,vdc2,vdc3</code>'
942+ _ ('VDC names separated by commas, encased with double quotes. Example:' ) + ' <code>" vdc1,vdc2,vdc3" </code>'
942943 )
943944 )
944945 type = CSVChoiceField (
@@ -967,7 +968,41 @@ class InterfaceImportForm(NetBoxModelImportForm):
967968 label = _ ('Mode' ),
968969 choices = InterfaceModeChoices ,
969970 required = False ,
970- help_text = _ ('IEEE 802.1Q operational mode (for L2 interfaces)' )
971+ help_text = _ ('IEEE 802.1Q operational mode (for L2 interfaces)' ),
972+ )
973+ vlan_group = CSVModelChoiceField (
974+ label = _ ('VLAN group' ),
975+ queryset = VLANGroup .objects .all (),
976+ required = False ,
977+ to_field_name = 'name' ,
978+ help_text = _ ('Filter VLANs available for assignment by group' ),
979+ )
980+ untagged_vlan = CSVModelChoiceField (
981+ label = _ ('Untagged VLAN' ),
982+ queryset = VLAN .objects .all (),
983+ required = False ,
984+ to_field_name = 'vid' ,
985+ help_text = _ ('Assigned untagged VLAN ID (filtered by VLAN group)' ),
986+ )
987+ tagged_vlans = CSVModelMultipleChoiceField (
988+ label = _ ('Tagged VLANs' ),
989+ queryset = VLAN .objects .all (),
990+ required = False ,
991+ to_field_name = 'vid' ,
992+ help_text = mark_safe (
993+ _ (
994+ 'Assigned tagged VLAN IDs separated by commas, encased with double quotes '
995+ '(filtered by VLAN group). Example:'
996+ )
997+ + ' <code>"100,200,300"</code>'
998+ ),
999+ )
1000+ qinq_svlan = CSVModelChoiceField (
1001+ label = _ ('Q-in-Q Service VLAN' ),
1002+ queryset = VLAN .objects .filter (qinq_role = VLANQinQRoleChoices .ROLE_SERVICE ),
1003+ required = False ,
1004+ to_field_name = 'vid' ,
1005+ help_text = _ ('Assigned Q-in-Q Service VLAN ID (filtered by VLAN group)' ),
9711006 )
9721007 vrf = CSVModelChoiceField (
9731008 label = _ ('VRF' ),
@@ -988,7 +1023,8 @@ class Meta:
9881023 fields = (
9891024 'device' , 'name' , 'label' , 'parent' , 'bridge' , 'lag' , 'type' , 'speed' , 'duplex' , 'enabled' ,
9901025 'mark_connected' , 'wwn' , 'vdcs' , 'mtu' , 'mgmt_only' , 'description' , 'poe_mode' , 'poe_type' , 'mode' ,
991- 'vrf' , 'rf_role' , 'rf_channel' , 'rf_channel_frequency' , 'rf_channel_width' , 'tx_power' , 'tags'
1026+ 'vlan_group' , 'untagged_vlan' , 'tagged_vlans' , 'qinq_svlan' , 'vrf' , 'rf_role' , 'rf_channel' ,
1027+ 'rf_channel_frequency' , 'rf_channel_width' , 'tx_power' , 'tags'
9921028 )
9931029
9941030 def __init__ (self , data = None , * args , ** kwargs ):
@@ -1005,6 +1041,13 @@ def __init__(self, data=None, *args, **kwargs):
10051041 self .fields ['lag' ].queryset = self .fields ['lag' ].queryset .filter (** params )
10061042 self .fields ['vdcs' ].queryset = self .fields ['vdcs' ].queryset .filter (** params )
10071043
1044+ # Limit choices for VLANs to the assigned VLAN group
1045+ if vlan_group := data .get ('vlan_group' ):
1046+ params = {f"group__{ self .fields ['vlan_group' ].to_field_name } " : vlan_group }
1047+ self .fields ['untagged_vlan' ].queryset = self .fields ['untagged_vlan' ].queryset .filter (** params )
1048+ self .fields ['tagged_vlans' ].queryset = self .fields ['tagged_vlans' ].queryset .filter (** params )
1049+ self .fields ['qinq_svlan' ].queryset = self .fields ['qinq_svlan' ].queryset .filter (** params )
1050+
10081051 def clean_enabled (self ):
10091052 # Make sure enabled is True when it's not included in the uploaded data
10101053 if 'enabled' not in self .data :
0 commit comments