diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index eb38b8102..79cad0a6b 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -167,7 +167,9 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm ) rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), required=False, label='Rack', widget=APISelect( @@ -177,7 +179,10 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm ) device = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'site', 'rack': 'rack'}, + chains=( + ('site', 'site'), + ('rack', 'rack'), + ), required=False, label='Device', widget=APISelect( @@ -186,20 +191,13 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm attrs={'filter-for': 'interface'} ) ) - livesearch = forms.CharField( - required=False, - label='Device', - widget=Livesearch( - query_key='q', - query_url='dcim-api:device-list', - field_to_update='device' - ) - ) interface = ChainedModelChoiceField( queryset=Interface.objects.exclude(form_factor__in=VIRTUAL_IFACE_TYPES).select_related( 'circuit_termination', 'connected_as_a', 'connected_as_b' ), - chains={'device': 'device'}, + chains=( + ('device', 'device'), + ), required=False, label='Interface', widget=APISelect( @@ -210,8 +208,10 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm class Meta: model = CircuitTermination - fields = ['term_side', 'site', 'rack', 'device', 'livesearch', 'interface', 'port_speed', 'upstream_speed', - 'xconnect_id', 'pp_info'] + fields = [ + 'term_side', 'site', 'rack', 'device', 'interface', 'port_speed', 'upstream_speed', 'xconnect_id', + 'pp_info', + ] help_texts = { 'port_speed': "Physical circuit speed", 'xconnect_id': "ID of the local cross-connect", diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 03fddf21d..9e1cc657d 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -190,7 +190,9 @@ class RackRoleForm(BootstrapMixin, forms.ModelForm): class RackForm(BootstrapMixin, TenancyForm, CustomFieldForm): group = ChainedModelChoiceField( queryset=RackGroup.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), required=False, widget=APISelect( api_url='/api/dcim/rack-groups/?site_id={{site}}', @@ -545,7 +547,9 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm): ) rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), required=False, widget=APISelect( api_url='/api/dcim/racks/?site_id={{site}}', @@ -570,7 +574,9 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm): ) device_type = ChainedModelChoiceField( queryset=DeviceType.objects.all(), - chains={'manufacturer': 'manufacturer'}, + chains=( + ('manufacturer', 'manufacturer'), + ), label='Device type', widget=APISelect( api_url='/api/dcim/device-types/?manufacturer_id={{manufacturer}}', @@ -957,20 +963,29 @@ class ConsoleConnectionImportForm(BootstrapMixin, BulkImportForm): class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): site = forms.ModelChoiceField( queryset=Site.objects.all(), - widget=forms.HiddenInput(), + required=False, + widget=forms.Select( + attrs={'filter-for': 'rack'} + ) ) rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), label='Rack', required=False, - widget=forms.Select( + widget=APISelect( + api_url='/api/dcim/racks/?site_id={{site}}', attrs={'filter-for': 'console_server', 'nullable': 'true'} ) ) console_server = ChainedModelChoiceField( queryset=Device.objects.filter(device_type__is_console_server=True), - chains={'site': 'site', 'rack': 'rack'}, + chains=( + ('site', 'site'), + ('rack', 'rack'), + ), label='Console Server', required=False, widget=APISelect( @@ -990,7 +1005,9 @@ class ConsolePortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelF ) cs_port = ChainedModelChoiceField( queryset=ConsoleServerPort.objects.all(), - chains={'device': 'console_server'}, + chains=( + ('device', 'console_server'), + ), label='Port', widget=APISelect( api_url='/api/dcim/console-server-ports/?device_id={{console_server}}', @@ -1035,20 +1052,29 @@ class ConsoleServerPortCreateForm(DeviceComponentForm): class ConsoleServerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): site = forms.ModelChoiceField( queryset=Site.objects.all(), - widget=forms.HiddenInput(), + required=False, + widget=forms.Select( + attrs={'filter-for': 'rack'} + ) ) rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), label='Rack', required=False, - widget=forms.Select( + widget=APISelect( + api_url='/api/dcim/racks/?site_id={{site}}', attrs={'filter-for': 'device', 'nullable': 'true'} ) ) device = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'site', 'rack': 'rack'}, + chains=( + ('site', 'site'), + ('rack', 'rack'), + ), label='Device', required=False, widget=APISelect( @@ -1068,7 +1094,9 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms. ) port = ChainedModelChoiceField( queryset=ConsolePort.objects.all(), - chains={'device': 'device'}, + chains=( + ('device', 'device'), + ), label='Port', widget=APISelect( api_url='/api/dcim/console-ports/?device_id={{device}}', @@ -1182,19 +1210,31 @@ class PowerConnectionImportForm(BootstrapMixin, BulkImportForm): class PowerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): - site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.HiddenInput()) - rack = ChainedModelChoiceField( - queryset=Rack.objects.all(), - chains={'site': 'site'}, - label='Rack', + site = forms.ModelChoiceField( + queryset=Site.objects.all(), required=False, widget=forms.Select( + attrs={'filter-for': 'rack'} + ) + ) + rack = ChainedModelChoiceField( + queryset=Rack.objects.all(), + chains=( + ('site', 'site'), + ), + label='Rack', + required=False, + widget=APISelect( + api_url='/api/dcim/racks/?site_id={{site}}', attrs={'filter-for': 'pdu', 'nullable': 'true'} ) ) pdu = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'site', 'rack': 'rack'}, + chains=( + ('site', 'site'), + ('rack', 'rack'), + ), label='PDU', required=False, widget=APISelect( @@ -1214,7 +1254,9 @@ class PowerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor ) power_outlet = ChainedModelChoiceField( queryset=PowerOutlet.objects.all(), - chains={'device': 'pdu'}, + chains=( + ('device', 'pdu'), + ), label='Outlet', widget=APISelect( api_url='/api/dcim/power-outlets/?device_id={{pdu}}', @@ -1259,20 +1301,29 @@ class PowerOutletCreateForm(DeviceComponentForm): class PowerOutletConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): site = forms.ModelChoiceField( queryset=Site.objects.all(), - widget=forms.HiddenInput() + required=False, + widget=forms.Select( + attrs={'filter-for': 'rack'} + ) ) rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), label='Rack', required=False, - widget=forms.Select( + widget=APISelect( + api_url='/api/dcim/racks/?site_id={{site}}', attrs={'filter-for': 'device', 'nullable': 'true'} ) ) device = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'site', 'rack': 'rack'}, + chains=( + ('site', 'site'), + ('rack', 'rack'), + ), label='Device', required=False, widget=APISelect( @@ -1292,7 +1343,9 @@ class PowerOutletConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form): ) port = ChainedModelChoiceField( queryset=PowerPort.objects.all(), - chains={'device': 'device'}, + chains=( + ('device', 'device'), + ), label='Port', widget=APISelect( api_url='/api/dcim/power-ports/?device_id={{device}}', @@ -1412,7 +1465,9 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor ) rack_b = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'site_b'}, + chains=( + ('site', 'site_b'), + ), label='Rack', required=False, widget=APISelect( @@ -1422,7 +1477,10 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor ) device_b = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'site_b', 'rack': 'rack_b'}, + chains=( + ('site', 'site_b'), + ('rack', 'rack_b'), + ), label='Device', required=False, widget=APISelect( @@ -1444,7 +1502,9 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor queryset=Interface.objects.exclude(form_factor__in=VIRTUAL_IFACE_TYPES).select_related( 'circuit_termination', 'connected_as_a', 'connected_as_b' ), - chains={'device': 'device_b'}, + chains=( + ('device', 'device_b'), + ), label='Interface', widget=APISelect( api_url='/api/dcim/interfaces/?device_id={{device_b}}&type=physical', diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 322e88b72..f6e00be04 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -944,9 +944,9 @@ def consoleport_connect(request, pk): else: form = forms.ConsolePortConnectionForm(instance=consoleport, initial={ - 'site': request.GET.get('site', consoleport.device.site), - 'rack': request.GET.get('rack', None), - 'console_server': request.GET.get('console_server', None), + 'site': request.GET.get('site'), + 'rack': request.GET.get('rack'), + 'console_server': request.GET.get('console_server'), 'connection_status': CONNECTION_STATUS_CONNECTED, }) @@ -1061,9 +1061,9 @@ def consoleserverport_connect(request, pk): else: form = forms.ConsoleServerPortConnectionForm(initial={ - 'site': request.GET.get('site', consoleserverport.device.site), - 'rack': request.GET.get('rack', None), - 'device': request.GET.get('device', None), + 'site': request.GET.get('site'), + 'rack': request.GET.get('rack'), + 'device': request.GET.get('device'), 'connection_status': CONNECTION_STATUS_CONNECTED, }) @@ -1167,9 +1167,9 @@ def powerport_connect(request, pk): else: form = forms.PowerPortConnectionForm(instance=powerport, initial={ - 'site': request.GET.get('site', powerport.device.site), - 'rack': request.GET.get('rack', None), - 'pdu': request.GET.get('pdu', None), + 'site': request.GET.get('site'), + 'rack': request.GET.get('rack'), + 'pdu': request.GET.get('pdu'), 'connection_status': CONNECTION_STATUS_CONNECTED, }) @@ -1284,9 +1284,9 @@ def poweroutlet_connect(request, pk): else: form = forms.PowerOutletConnectionForm(initial={ - 'site': request.GET.get('site', poweroutlet.device.site), - 'rack': request.GET.get('rack', None), - 'device': request.GET.get('device', None), + 'site': request.GET.get('site'), + 'rack': request.GET.get('rack'), + 'device': request.GET.get('device'), 'connection_status': CONNECTION_STATUS_CONNECTED, }) @@ -1616,11 +1616,11 @@ def interfaceconnection_add(request, pk): else: form = forms.InterfaceConnectionForm(device, initial={ - 'interface_a': request.GET.get('interface_a', None), - 'site_b': request.GET.get('site_b', device.site), - 'rack_b': request.GET.get('rack_b', None), - 'device_b': request.GET.get('device_b', None), - 'interface_b': request.GET.get('interface_b', None), + 'interface_a': request.GET.get('interface_a'), + 'site_b': request.GET.get('site_b'), + 'rack_b': request.GET.get('rack_b'), + 'device_b': request.GET.get('device_b'), + 'interface_b': request.GET.get('interface_b'), }) return render(request, 'dcim/interfaceconnection_edit.html', { diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 7f62015af..3bc8124ea 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -168,12 +168,21 @@ class RoleForm(BootstrapMixin, forms.ModelForm): class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm): site = forms.ModelChoiceField( - queryset=Site.objects.all(), required=False, label='Site', widget=forms.Select( + queryset=Site.objects.all(), + required=False, + label='Site', + widget=forms.Select( attrs={'filter-for': 'vlan', 'nullable': 'true'} ) ) vlan = ChainedModelChoiceField( - queryset=VLAN.objects.all(), chains={'site': 'site'}, required=False, label='VLAN', widget=APISelect( + queryset=VLAN.objects.all(), + chains=( + ('site', 'site'), + ), + required=False, + label='VLAN', + widget=APISelect( api_url='/api/ipam/vlans/?site_id={{site}}', display_field='display_name' ) ) @@ -322,7 +331,9 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) ) interface_rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'interface_site'}, + chains=( + ('site', 'interface_site'), + ), required=False, label='Rack', widget=APISelect( @@ -333,7 +344,10 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) ) interface_device = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'interface_site', 'rack': 'interface_rack'}, + chains=( + ('site', 'interface_site'), + ('rack', 'interface_rack'), + ), required=False, label='Device', widget=APISelect( @@ -344,7 +358,9 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) ) interface = ChainedModelChoiceField( queryset=Interface.objects.all(), - chains={'device': 'interface_device'}, + chains=( + ('device', 'interface_device'), + ), required=False, widget=APISelect( api_url='/api/dcim/interfaces/?device_id={{interface_device}}' @@ -355,34 +371,41 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) required=False, label='Site', widget=forms.Select( - attrs={'filter-for': 'nat_device'} + attrs={'filter-for': 'nat_rack'} ) ) nat_rack = ChainedModelChoiceField( queryset=Rack.objects.all(), - chains={'site': 'nat_site'}, + chains=( + ('site', 'nat_site'), + ), required=False, label='Rack', widget=APISelect( - api_url='/api/dcim/racks/?site_id={{interface_site}}', + api_url='/api/dcim/racks/?site_id={{nat_site}}', display_field='display_name', attrs={'filter-for': 'nat_device', 'nullable': 'true'} ) ) nat_device = ChainedModelChoiceField( queryset=Device.objects.all(), - chains={'site': 'nat_site'}, + chains=( + ('site', 'nat_site'), + ('rack', 'nat_rack'), + ), required=False, label='Device', widget=APISelect( - api_url='/api/dcim/devices/?site_id={{nat_site}}', + api_url='/api/dcim/devices/?site_id={{nat_site}}&rack_id={{nat_rack}}', display_field='display_name', attrs={'filter-for': 'nat_inside'} ) ) nat_inside = ChainedModelChoiceField( queryset=IPAddress.objects.all(), - chains={'interface__device': 'nat_device'}, + chains=( + ('interface__device', 'nat_device'), + ), required=False, label='IP Address', widget=APISelect( @@ -392,7 +415,7 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) ) livesearch = forms.CharField( required=False, - label='IP Address', + label='Search', widget=Livesearch( query_key='q', query_url='ipam-api:ipaddress-list', @@ -405,8 +428,8 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm) class Meta: model = IPAddress fields = [ - 'address', 'vrf', 'status', 'description', 'interface', 'primary_for_device', 'nat_inside', 'tenant_group', - 'tenant', + 'address', 'vrf', 'status', 'description', 'interface', 'primary_for_device', 'nat_site', 'nat_rack', + 'nat_inside', 'tenant_group', 'tenant', ] def __init__(self, *args, **kwargs): @@ -627,7 +650,9 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm): ) group = ChainedModelChoiceField( queryset=VLANGroup.objects.all(), - chains={'site': 'site'}, + chains=( + ('site', 'site'), + ), required=False, label='Group', widget=APISelect( diff --git a/netbox/templates/circuits/circuittermination_edit.html b/netbox/templates/circuits/circuittermination_edit.html index 22e02c4ee..13aa7e5b6 100644 --- a/netbox/templates/circuits/circuittermination_edit.html +++ b/netbox/templates/circuits/circuittermination_edit.html @@ -45,23 +45,8 @@ {% render_field form.site %} -
-
- -
-
-
-
- {% render_field form.rack %} - {% render_field form.device %} -
- -
+ {% render_field form.rack %} + {% render_field form.device %} {% render_field form.interface %} diff --git a/netbox/templates/dcim/consoleport_connect.html b/netbox/templates/dcim/consoleport_connect.html index a04a4674b..e06bf45ec 100644 --- a/netbox/templates/dcim/consoleport_connect.html +++ b/netbox/templates/dcim/consoleport_connect.html @@ -32,12 +32,7 @@ {% render_field form.livesearch %}
-
- -
-

{{ consoleport.device.site }}

-
-
+ {% render_field form.site %} {% render_field form.rack %} {% render_field form.console_server %}
diff --git a/netbox/templates/dcim/consoleserverport_connect.html b/netbox/templates/dcim/consoleserverport_connect.html index 6ba944b59..82b80e3f7 100644 --- a/netbox/templates/dcim/consoleserverport_connect.html +++ b/netbox/templates/dcim/consoleserverport_connect.html @@ -32,12 +32,7 @@ {% render_field form.livesearch %}
-
- -
-

{{ consoleserverport.device.site }}

-
-
+ {% render_field form.site %} {% render_field form.rack %} {% render_field form.device %}
diff --git a/netbox/templates/dcim/poweroutlet_connect.html b/netbox/templates/dcim/poweroutlet_connect.html index 6fcc3e858..839027db2 100644 --- a/netbox/templates/dcim/poweroutlet_connect.html +++ b/netbox/templates/dcim/poweroutlet_connect.html @@ -32,12 +32,7 @@ {% render_field form.livesearch %}
-
- -
-

{{ poweroutlet.device.site }}

-
-
+ {% render_field form.site %} {% render_field form.rack %} {% render_field form.device %}
diff --git a/netbox/templates/dcim/powerport_connect.html b/netbox/templates/dcim/powerport_connect.html index f77a0e352..a10fecc7b 100644 --- a/netbox/templates/dcim/powerport_connect.html +++ b/netbox/templates/dcim/powerport_connect.html @@ -32,12 +32,7 @@ {% render_field form.livesearch %}
-
- -
-

{{ powerport.device.site }}

-
-
+ {% render_field form.site %} {% render_field form.rack %} {% render_field form.pdu %}
diff --git a/netbox/templates/ipam/ipaddress_edit.html b/netbox/templates/ipam/ipaddress_edit.html index d7aef0fe4..64dc22353 100644 --- a/netbox/templates/ipam/ipaddress_edit.html +++ b/netbox/templates/ipam/ipaddress_edit.html @@ -47,6 +47,7 @@
{% render_field form.nat_site %} + {% render_field form.nat_rack %} {% render_field form.nat_device %}