diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 4d332e904..8222d3d26 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2180,6 +2180,10 @@ class ConsolePortForm(BootstrapMixin, forms.ModelForm): class ConsolePortCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -2238,6 +2242,10 @@ class ConsoleServerPortForm(BootstrapMixin, forms.ModelForm): class ConsoleServerPortCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -2331,6 +2339,10 @@ class PowerPortForm(BootstrapMixin, forms.ModelForm): class PowerPortCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -2412,6 +2424,10 @@ class PowerOutletForm(BootstrapMixin, forms.ModelForm): class PowerOutletCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -2437,11 +2453,12 @@ class PowerOutletCreateForm(ComponentForm): ) def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Limit power_port choices to those on the parent device - self.fields['power_port'].queryset = PowerPort.objects.filter(device=self.parent) + # Limit power_port queryset to PowerPorts which belong to the parent Device + if 'device' in self.initial: + device = Device.objects.filter(pk=self.initial['device']).first() + self.fields['power_port'].queryset = PowerPort.objects.filter(device=device) class PowerOutletCSVForm(forms.ModelForm): @@ -2631,7 +2648,8 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form): widget=StaticSelect2(), ) enabled = forms.BooleanField( - required=False + required=False, + initial=True ) lag = forms.ModelChoiceField( queryset=Interface.objects.all(), @@ -2686,21 +2704,15 @@ class InterfaceCreateForm(InterfaceCommonForm, ComponentForm, forms.Form): ) def __init__(self, *args, **kwargs): - - # Set interfaces enabled by default - kwargs['initial'] = kwargs.get('initial', {}).copy() - kwargs['initial'].update({'enabled': True}) - super().__init__(*args, **kwargs) - # Limit LAG choices to interfaces belonging to this device (or its VC master) - if self.parent is not None: + # Limit LAG choices to interfaces which belong to the parent device (or VC master) + if 'device' in self.initial: + device = Device.objects.filter(pk=self.initial['device']).first() self.fields['lag'].queryset = Interface.objects.filter( - device__in=[self.parent, self.parent.get_vc_master()], + device__in=[device, device.get_vc_master()], type=InterfaceTypeChoices.TYPE_LAG ) - else: - self.fields['lag'].queryset = Interface.objects.none() class InterfaceCSVForm(forms.ModelForm): @@ -2917,6 +2929,10 @@ class FrontPortForm(BootstrapMixin, forms.ModelForm): # TODO: Merge with FrontPortTemplateCreateForm to remove duplicate logic class FrontPortCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -2936,15 +2952,17 @@ class FrontPortCreateForm(ComponentForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + parent = Device.objects.get(pk=self.initial['device']) + # 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 self.parent.frontports.all() + for front_port in parent.frontports.all() ] # Populate rear port choices choices = [] - rear_ports = RearPort.objects.filter(device=self.parent) + rear_ports = RearPort.objects.filter(device=parent) 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: @@ -3084,6 +3102,10 @@ class RearPortForm(BootstrapMixin, forms.ModelForm): class RearPortCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) @@ -3688,6 +3710,10 @@ class DeviceBayForm(BootstrapMixin, forms.ModelForm): class DeviceBayCreateForm(ComponentForm): + device = forms.ModelChoiceField( + queryset=Device.objects.all(), + widget=forms.HiddenInput() + ) name_pattern = ExpandableNameField( label='Name' ) diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index c6057b4a3..121beff97 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -169,8 +169,8 @@ urlpatterns = [ # Console ports path(r'devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'), - path(r'devices//console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'), path(r'console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'), + path(r'console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'), path(r'console-ports/import/', views.ConsolePortBulkImportView.as_view(), name='consoleport_import'), # TODO: Bulk edit view for ConsolePorts path(r'console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'), @@ -181,10 +181,10 @@ urlpatterns = [ # Console server ports path(r'devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'), - path(r'devices//console-server-ports/add/', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'), path(r'console-server-ports/', views.ConsoleServerPortListView.as_view(), name='consoleserverport_list'), path(r'console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'), path(r'console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'), + path(r'console-server-ports/add/', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'), path(r'console-server-ports/import/', views.ConsoleServerPortBulkImportView.as_view(), name='consoleserverport_import'), path(r'console-server-ports/edit/', views.ConsoleServerPortBulkEditView.as_view(), name='consoleserverport_bulk_edit'), path(r'console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'), @@ -195,8 +195,8 @@ urlpatterns = [ # Power ports path(r'devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'), - path(r'devices//power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'), path(r'power-ports/', views.PowerPortListView.as_view(), name='powerport_list'), + path(r'power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'), path(r'power-ports/import/', views.PowerPortBulkImportView.as_view(), name='powerport_import'), # TODO: Bulk edit view for PowerPorts path(r'power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'), @@ -207,10 +207,10 @@ urlpatterns = [ # Power outlets path(r'devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'), - path(r'devices//power-outlets/add/', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'), path(r'power-outlets/', views.PowerOutletListView.as_view(), name='poweroutlet_list'), path(r'power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'), path(r'power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'), + path(r'power-outlets/add/', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'), path(r'power-outlets/import/', views.PowerOutletBulkImportView.as_view(), name='poweroutlet_import'), path(r'power-outlets/edit/', views.PowerOutletBulkEditView.as_view(), name='poweroutlet_bulk_edit'), path(r'power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'), @@ -221,10 +221,10 @@ urlpatterns = [ # Interfaces path(r'devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'), - path(r'devices//interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'), path(r'interfaces/', views.InterfaceListView.as_view(), name='interface_list'), path(r'interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'), path(r'interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'), + path(r'interfaces/add/', views.InterfaceCreateView.as_view(), name='interface_add'), path(r'interfaces/import/', views.InterfaceBulkImportView.as_view(), name='interface_import'), path(r'interfaces/edit/', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'), path(r'interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'), @@ -237,10 +237,10 @@ urlpatterns = [ # Front ports # path(r'devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'), - path(r'devices//front-ports/add/', views.FrontPortCreateView.as_view(), name='frontport_add'), path(r'front-ports/', views.FrontPortListView.as_view(), name='frontport_list'), path(r'front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'), path(r'front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'), + path(r'front-ports/add/', views.FrontPortCreateView.as_view(), name='frontport_add'), path(r'front-ports/import/', views.FrontPortBulkImportView.as_view(), name='frontport_import'), path(r'front-ports/edit/', views.FrontPortBulkEditView.as_view(), name='frontport_bulk_edit'), path(r'front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'), @@ -251,10 +251,10 @@ urlpatterns = [ # Rear ports # path(r'devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'), - path(r'devices//rear-ports/add/', views.RearPortCreateView.as_view(), name='rearport_add'), path(r'rear-ports/', views.RearPortListView.as_view(), name='rearport_list'), path(r'rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'), path(r'rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'), + path(r'rear-ports/add/', views.RearPortCreateView.as_view(), name='rearport_add'), path(r'rear-ports/import/', views.RearPortBulkImportView.as_view(), name='rearport_import'), path(r'rear-ports/edit/', views.RearPortBulkEditView.as_view(), name='rearport_bulk_edit'), path(r'rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'), @@ -265,9 +265,9 @@ urlpatterns = [ # Device bays path(r'devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'), - path(r'devices//bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'), path(r'device-bays/', views.DeviceBayListView.as_view(), name='devicebay_list'), path(r'device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'), + path(r'device-bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'), path(r'device-bays/import/', views.DeviceBayBulkImportView.as_view(), name='devicebay_import'), # TODO: Bulk edit view for DeviceBays path(r'device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'), @@ -283,6 +283,7 @@ urlpatterns = [ path(r'inventory-items/delete/', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'), path(r'inventory-items//edit/', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'), path(r'inventory-items//delete/', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'), + # TODO: Replace below with InventoryItemCreateView path(r'devices//inventory-items/add/', views.InventoryItemEditView.as_view(), name='inventoryitem_add'), # Cables diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 9d9223e29..6e7018fb5 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1205,8 +1205,6 @@ class ConsolePortListView(PermissionRequiredMixin, ObjectListView): class ConsolePortCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_consoleport' - parent_model = Device - parent_field = 'device' model = ConsolePort form = forms.ConsolePortCreateForm model_form = forms.ConsolePortForm @@ -1253,8 +1251,6 @@ class ConsoleServerPortListView(PermissionRequiredMixin, ObjectListView): class ConsoleServerPortCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_consoleserverport' - parent_model = Device - parent_field = 'device' model = ConsoleServerPort form = forms.ConsoleServerPortCreateForm model_form = forms.ConsoleServerPortForm @@ -1320,8 +1316,6 @@ class PowerPortListView(PermissionRequiredMixin, ObjectListView): class PowerPortCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_powerport' - parent_model = Device - parent_field = 'device' model = PowerPort form = forms.PowerPortCreateForm model_form = forms.PowerPortForm @@ -1368,8 +1362,6 @@ class PowerOutletListView(PermissionRequiredMixin, ObjectListView): class PowerOutletCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_poweroutlet' - parent_model = Device - parent_field = 'device' model = PowerOutlet form = forms.PowerOutletCreateForm model_form = forms.PowerOutletForm @@ -1471,8 +1463,6 @@ class InterfaceView(PermissionRequiredMixin, View): class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_interface' - parent_model = Device - parent_field = 'device' model = Interface form = forms.InterfaceCreateForm model_form = forms.InterfaceForm @@ -1539,8 +1529,6 @@ class FrontPortListView(PermissionRequiredMixin, ObjectListView): class FrontPortCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_frontport' - parent_model = Device - parent_field = 'device' model = FrontPort form = forms.FrontPortCreateForm model_form = forms.FrontPortForm @@ -1606,8 +1594,6 @@ class RearPortListView(PermissionRequiredMixin, ObjectListView): class RearPortCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_rearport' - parent_model = Device - parent_field = 'device' model = RearPort form = forms.RearPortCreateForm model_form = forms.RearPortForm @@ -1675,8 +1661,6 @@ class DeviceBayListView(PermissionRequiredMixin, ObjectListView): class DeviceBayCreateView(PermissionRequiredMixin, ComponentCreateView): permission_required = 'dcim.add_devicebay' - parent_model = Device - parent_field = 'device' model = DeviceBay form = forms.DeviceBayCreateForm model_form = forms.DeviceBayForm diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index c36671349..5ede19d78 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -48,14 +48,30 @@ Add Components {% endif %} @@ -333,12 +349,12 @@ {% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}