diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 70a220b58..23540a507 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -106,17 +106,15 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False + required=False, + query_params={ + 'region': '$region' + } ) asn = forms.IntegerField( required=False, @@ -282,17 +280,15 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False + required=False, + query_params={ + 'region': '$region' + } ) commit_rate = forms.IntegerField( required=False, diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 7e7a75125..dc79e40f0 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -68,27 +68,23 @@ class DeviceComponentFilterForm(BootstrapMixin, forms.Form): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'device_id': 'site', - } - ) + query_params={ + 'region': '$region' + } ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, - label='Device' + label='Device', + query_params={ + 'site': '$site' + } ) @@ -357,16 +353,14 @@ class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class RackGroupForm(BootstrapMixin, forms.ModelForm): site = DynamicModelChoiceField( - queryset=Site.objects.all(), - widget=APISelect( - filter_for={ - 'parent': 'site_id', - } - ) + queryset=Site.objects.all() ) parent = DynamicModelChoiceField( queryset=RackGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) slug = SlugField() @@ -402,28 +396,24 @@ class RackGroupFilterForm(BootstrapMixin, forms.Form): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region', - 'parent': 'region', - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'parent': 'site', - } - ) + query_params={ + 'region': '$region' + } ) parent = DynamicModelMultipleChoiceField( queryset=RackGroup.objects.all(), to_field_name='slug', - required=False + required=False, + query_params={ + 'region': '$region', + 'site': '$site', + } ) @@ -458,16 +448,14 @@ class RackRoleCSVForm(CSVModelForm): class RackForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): site = DynamicModelChoiceField( - queryset=Site.objects.all(), - widget=APISelect( - filter_for={ - 'group': 'site_id', - } - ) + queryset=Site.objects.all() ) group = DynamicModelChoiceField( queryset=RackGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) role = DynamicModelChoiceField( queryset=RackRole.objects.all(), @@ -562,16 +550,14 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor ) site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'group': 'site_id', - } - ) + required=False ) group = DynamicModelChoiceField( queryset=RackGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -649,30 +635,24 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'group_id': 'site' - } - ) + query_params={ + 'region': '$region' + } ) group_id = DynamicModelMultipleChoiceField( - queryset=RackGroup.objects.prefetch_related( - 'site' - ), + queryset=RackGroup.objects.all(), required=False, label='Rack group', - null_option='None' + null_option='None', + query_params={ + 'site': '$site' + } ) status = forms.MultipleChoiceField( choices=RackStatusChoices, @@ -698,16 +678,13 @@ class RackElevationFilterForm(RackFilterForm): queryset=Rack.objects.all(), label='Rack', required=False, - display_field='display_name' + display_field='display_name', + query_params={ + 'site': '$site', + 'group_id': '$group_id', + } ) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Filter the rack field based on the site and group - self.fields['site'].widget.add_filter_for('id', 'site') - self.fields['group_id'].widget.add_filter_for('id', 'group_id') - # # Rack reservations @@ -716,25 +693,21 @@ class RackElevationFilterForm(RackFilterForm): class RackReservationForm(BootstrapMixin, TenancyForm, forms.ModelForm): site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'rack_group': 'site_id', - 'rack': 'site_id', - } - ) + required=False ) rack_group = DynamicModelChoiceField( queryset=RackGroup.objects.all(), required=False, - widget=APISelect( - filter_for={ - 'rack': 'group_id' - } - ) + query_params={ + 'site_id': '$site' + } ) rack = DynamicModelChoiceField( - queryset=Rack.objects.all() + queryset=Rack.objects.all(), + query_params={ + 'site_id': '$site', + 'group_id': 'rack', + } ) units = NumericArrayField( base_field=forms.IntegerField(), @@ -1011,16 +984,14 @@ class ComponentTemplateCreateForm(ComponentForm): """ manufacturer = DynamicModelChoiceField( queryset=Manufacturer.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'device_type': 'manufacturer_id' - } - ) + required=False ) device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), - display_field='model' + display_field='model', + query_params={ + 'manufacturer_id': '$manufacturer' + } ) description = forms.CharField( required=False @@ -1699,17 +1670,15 @@ class PlatformCSVForm(CSVModelForm): class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): site = DynamicModelChoiceField( - queryset=Site.objects.all(), - widget=APISelect( - filter_for={ - 'rack': 'site_id' - } - ) + queryset=Site.objects.all() ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, - display_field='display_name' + display_field='display_name', + query_params={ + 'site_id': '$site' + } ) position = forms.TypedChoiceField( required=False, @@ -1717,22 +1686,22 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): help_text="The lowest-numbered unit occupied by the device", widget=APISelect( api_url='/api/dcim/racks/{{rack}}/elevation/', - disabled_indicator='device' + disabled_indicator='device', + additional_query_params={ + 'face': '$face' + } ) ) manufacturer = DynamicModelChoiceField( queryset=Manufacturer.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'device_type': 'manufacturer_id', - 'platform': 'manufacturer_id' - } - ) + required=False ) device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), - display_field='model' + display_field='model', + query_params={ + 'manufacturer_id': '$manufacturer' + } ) device_role = DynamicModelChoiceField( queryset=DeviceRole.objects.all() @@ -1741,22 +1710,20 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): queryset=Platform.objects.all(), required=False, query_params={ - "manufacturer_id": "null" + 'manufacturer_id': ['$manufacturer', 'null'] } ) cluster_group = DynamicModelChoiceField( queryset=ClusterGroup.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - 'cluster': 'group_id' - } - ) + null_option='None' ) cluster = DynamicModelChoiceField( queryset=Cluster.objects.all(), - required=False + required=False, + query_params={ + 'group_id': '$cluster_group' + } ) comments = CommentField() local_context_data = JSONField( @@ -1782,11 +1749,6 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): "config context", } widgets = { - 'face': StaticSelect2( - filter_for={ - 'position': 'face' - } - ), 'status': StaticSelect2(), 'primary_ip4': StaticSelect2(), 'primary_ip6': StaticSelect2(), @@ -2084,39 +2046,33 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'rack_group_id': 'site', - 'rack_id': 'site', - } - ) + query_params={ + 'region': '$region' + } ) rack_group_id = DynamicModelMultipleChoiceField( queryset=RackGroup.objects.all(), required=False, label='Rack group', - widget=APISelectMultiple( - filter_for={ - 'rack_id': 'group_id', - } - ) + query_params={ + 'site': '$site' + } ) rack_id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), required=False, label='Rack', - null_option='None' + null_option='None', + query_params={ + 'site': '$site', + 'group_id': '$rack_group_id', + } ) role = DynamicModelMultipleChoiceField( queryset=DeviceRole.objects.all(), @@ -2125,21 +2081,20 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt widget=APISelectMultiple( ) ) - manufacturer_id = DynamicModelMultipleChoiceField( + manufacturer = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), + to_field_name='slug', required=False, - label='Manufacturer', - widget=APISelectMultiple( - filter_for={ - 'device_type_id': 'manufacturer_id', - } - ) + label='Manufacturer' ) device_type_id = DynamicModelMultipleChoiceField( queryset=DeviceType.objects.all(), required=False, label='Model', - display_field='model' + display_field='model', + query_params={ + 'manufacturer': '$manufacturer' + } ) platform = DynamicModelMultipleChoiceField( queryset=Platform.objects.all(), @@ -3424,30 +3379,26 @@ class ConnectCableToDeviceForm(BootstrapMixin, forms.ModelForm): termination_b_site = DynamicModelChoiceField( queryset=Site.objects.all(), label='Site', - required=False, - widget=APISelect( - filter_for={ - 'termination_b_rack': 'site_id', - 'termination_b_device': 'site_id', - } - ) + required=False ) termination_b_rack = DynamicModelChoiceField( queryset=Rack.objects.all(), label='Rack', required=False, null_option='None', - widget=APISelect( - filter_for={ - 'termination_b_device': 'rack_id', - } - ) + query_params={ + 'site_id': '$termination_b_site' + } ) termination_b_device = DynamicModelChoiceField( queryset=Device.objects.all(), label='Device', required=False, display_field='display_name', + query_params={ + 'site_id': '$termination_b_site', + 'rack_id': '$termination_b_rack', + }, widget=APISelect( filter_for={ 'termination_b_id': 'device_id', @@ -3545,27 +3496,21 @@ class ConnectCableToCircuitTerminationForm(BootstrapMixin, forms.ModelForm): termination_b_provider = DynamicModelChoiceField( queryset=Provider.objects.all(), label='Provider', - required=False, - widget=APISelect( - filter_for={ - 'termination_b_circuit': 'provider_id', - } - ) + required=False ) termination_b_site = DynamicModelChoiceField( queryset=Site.objects.all(), label='Site', - required=False, - widget=APISelect( - filter_for={ - 'termination_b_circuit': 'site_id', - } - ) + required=False ) termination_b_circuit = DynamicModelChoiceField( queryset=Circuit.objects.all(), label='Circuit', display_field='cid', + query_params={ + 'provider_id': '$termination_b_provider', + 'site_id': '$termination_b_site', + }, widget=APISelect( filter_for={ 'termination_b_id': 'circuit_id', @@ -3595,29 +3540,25 @@ class ConnectCableToPowerFeedForm(BootstrapMixin, forms.ModelForm): queryset=Site.objects.all(), label='Site', required=False, - display_field='cid', - widget=APISelect( - filter_for={ - 'termination_b_rackgroup': 'site_id', - 'termination_b_powerpanel': 'site_id', - } - ) + display_field='cid' ) termination_b_rackgroup = DynamicModelChoiceField( queryset=RackGroup.objects.all(), label='Rack Group', required=False, display_field='cid', - widget=APISelect( - filter_for={ - 'termination_b_powerpanel': 'rackgroup_id', - } - ) + query_params={ + 'site_id': '$termination_b_site' + } ) termination_b_powerpanel = DynamicModelChoiceField( queryset=PowerPanel.objects.all(), label='Power Panel', required=False, + query_params={ + 'site_id': '$termination_b_site', + 'rack_group_id': '$termination_b_rackgroup', + }, widget=APISelect( filter_for={ 'termination_b_id': 'power_panel_id', @@ -3843,34 +3784,21 @@ class CableFilterForm(BootstrapMixin, forms.Form): site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'rack_id': 'site', - 'device_id': 'site', - } - ) + required=False ) tenant = DynamicModelMultipleChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'device_id': 'tenant', - } - ) + required=False ) rack_id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), required=False, label='Rack', null_option='None', - widget=APISelectMultiple( - filter_for={ - 'device_id': 'rack_id', - } - ) + query_params={ + 'site': '$site' + } ) type = forms.MultipleChoiceField( choices=add_blank_choice(CableTypeChoices), @@ -3890,7 +3818,12 @@ class CableFilterForm(BootstrapMixin, forms.Form): device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, - label='Device' + label='Device', + query_params={ + 'site': '$site', + 'tenant': '$tenant', + 'rack_id': '$rack_id', + } ) tag = TagFilterField(model) @@ -3903,17 +3836,15 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form): site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'device_id': 'site', - } - ) + required=False ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, - label='Device' + label='Device', + query_params={ + 'site': '$site' + } ) @@ -3921,17 +3852,15 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form): site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'device_id': 'site', - } - ) + required=False ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, - label='Device' + label='Device', + query_params={ + 'site': '$site' + } ) @@ -3939,17 +3868,15 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form): site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'device_id': 'site', - } - ) + required=False ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, - label='Device' + label='Device', + query_params={ + 'site': '$site' + } ) @@ -3967,27 +3894,23 @@ class DeviceSelectionForm(forms.Form): class VirtualChassisCreateForm(BootstrapMixin, forms.ModelForm): site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'rack': 'site_id', - 'members': 'site_id', - } - ) + required=False ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, null_option='None', - widget=APISelect( - filter_for={ - 'members': 'rack_id' - } - ) + query_params={ + 'site_id': '$site' + } ) members = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, + query_params={ + 'site_id': '$site', + 'rack_id': '$rack', + } ) initial_position = forms.IntegerField( initial=1, @@ -4101,29 +4024,23 @@ class DeviceVCMembershipForm(forms.ModelForm): class VCMemberSelectForm(BootstrapMixin, forms.Form): site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'rack': 'site_id', - 'device': 'site_id', - } - ) + required=False ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, null_option='None', - widget=APISelect( - filter_for={ - 'device': 'rack_id' - } - ) + query_params={ + 'site_id': '$site' + } ) device = DynamicModelChoiceField( queryset=Device.objects.all(), display_field='display_name', query_params={ - 'virtual_chassis_id': 'null' + 'site_id': '$site', + 'rack_id': '$rack', + 'virtual_chassis_id': 'null', } ) @@ -4172,34 +4089,30 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', - required=False + required=False, + query_params={ + 'region': '$region' + } ) tenant_group = DynamicModelMultipleChoiceField( queryset=TenantGroup.objects.all(), to_field_name='slug', required=False, - null_option='None', - widget=APISelectMultiple( - filter_for={ - 'tenant': 'group' - } - ) + null_option='None' ) tenant = DynamicModelMultipleChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'group': '$tenant_group' + } ) tag = TagFilterField(model) @@ -4210,16 +4123,14 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm): class PowerPanelForm(BootstrapMixin, forms.ModelForm): site = DynamicModelChoiceField( - queryset=Site.objects.all(), - widget=APISelect( - filter_for={ - 'rack_group': 'site_id', - } - ) + queryset=Site.objects.all() ) rack_group = DynamicModelChoiceField( queryset=RackGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), @@ -4266,16 +4177,14 @@ class PowerPanelBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): ) site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'rack_group': 'site_id', - } - ) + required=False ) rack_group = DynamicModelChoiceField( queryset=RackGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) class Meta: @@ -4293,28 +4202,24 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'rack_group_id': 'site', - } - ) + query_params={ + 'region': '$region' + } ) rack_group_id = DynamicModelMultipleChoiceField( queryset=RackGroup.objects.all(), required=False, label='Rack group (ID)', - null_option='None' + null_option='None', + query_params={ + 'site': '$site' + } ) tag = TagFilterField(model) @@ -4326,20 +4231,20 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm): class PowerFeedForm(BootstrapMixin, CustomFieldModelForm): site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'power_panel': 'site_id', - 'rack': 'site_id', - } - ) + required=False ) power_panel = DynamicModelChoiceField( - queryset=PowerPanel.objects.all() + queryset=PowerPanel.objects.all(), + query_params={ + 'site_id': '$site' + } ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) comments = CommentField() tags = DynamicModelMultipleChoiceField( @@ -4445,12 +4350,7 @@ class PowerFeedBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd ) power_panel = DynamicModelChoiceField( queryset=PowerPanel.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'rackgroup': 'site_id', - } - ) + required=False ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), @@ -4509,35 +4409,33 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - widget=APISelectMultiple( - filter_for={ - 'power_panel_id': 'site', - 'rack_id': 'site', - } - ) + query_params={ + 'region': '$region' + } ) power_panel_id = DynamicModelMultipleChoiceField( queryset=PowerPanel.objects.all(), required=False, label='Power panel', - null_option='None' + null_option='None', + query_params={ + 'site': '$site' + } ) rack_id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), required=False, label='Rack', - null_option='None' + null_option='None', + query_params={ + 'site': '$site' + } ) status = forms.MultipleChoiceField( choices=PowerFeedStatusChoices, diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index d86895b2c..cc83568b1 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -257,30 +257,26 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - 'vlan_group': 'site_id', - 'vlan': 'site_id', - } - ) + null_option='None' ) vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, label='VLAN group', null_option='None', - widget=APISelect( - filter_for={ - 'vlan': 'group_id' - } - ) + query_params={ + 'site_id': '$site' + } ) vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, label='VLAN', - display_field='display_name' + display_field='display_name', + query_params={ + 'site_id': '$site', + 'group_id': '$vlan_group', + } ) role = DynamicModelChoiceField( queryset=Role.objects.all(), @@ -470,18 +466,16 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm) region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) role = DynamicModelMultipleChoiceField( queryset=Role.objects.all(), @@ -506,30 +500,26 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm) class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModelForm): device = DynamicModelChoiceField( queryset=Device.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'interface': 'device_id' - } - ) + required=False ) interface = DynamicModelChoiceField( queryset=Interface.objects.all(), - required=False + required=False, + query_params={ + 'device_id': '$device' + } ) virtual_machine = DynamicModelChoiceField( queryset=VirtualMachine.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'vminterface': 'virtual_machine_id' - } - ) + required=False ) vminterface = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Interface' + label='Interface', + query_params={ + 'virtual_machine_id': '$virtual_machine' + } ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), @@ -539,13 +529,7 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel nat_site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - label='Site', - widget=APISelect( - filter_for={ - 'nat_rack': 'site_id', - 'nat_device': 'site_id' - } - ) + label='Site' ) nat_rack = DynamicModelChoiceField( queryset=Rack.objects.all(), @@ -553,38 +537,34 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel label='Rack', display_field='display_name', null_option='None', - widget=APISelect( - filter_for={ - 'nat_device': 'rack_id' - } - ) + query_params={ + 'site_id': '$site' + } ) nat_device = DynamicModelChoiceField( queryset=Device.objects.all(), required=False, label='Device', display_field='display_name', - widget=APISelect( - filter_for={ - 'nat_inside': 'device_id' - } - ) + query_params={ + 'site_id': '$site', + 'rack_id': '$nat_rack', + } ) nat_vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF', - widget=APISelect( - filter_for={ - 'nat_inside': 'vrf_id' - } - ) + label='VRF' ) nat_inside = DynamicModelChoiceField( queryset=IPAddress.objects.all(), required=False, label='IP Address', - display_field='address' + display_field='address', + query_params={ + 'device_id': '$nat_device', + 'vrf_if': '$nat_vrf', + } ) primary_for_parent = forms.BooleanField( required=False, @@ -956,18 +936,16 @@ class VLANGroupFilterForm(BootstrapMixin, forms.Form): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region', - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) @@ -979,16 +957,14 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - 'group': 'site_id' - } - ) + null_option='None' ) group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) role = DynamicModelChoiceField( queryset=Role.objects.all(), @@ -1072,16 +1048,14 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor ) site = DynamicModelChoiceField( queryset=Site.objects.all(), - required=False, - widget=APISelect( - filter_for={ - 'group': 'site_id' - } - ) + required=False ) group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), - required=False + required=False, + query_params={ + 'site_id': '$site' + } ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -1117,25 +1091,25 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region', - 'group_id': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) group_id = DynamicModelMultipleChoiceField( queryset=VLANGroup.objects.all(), required=False, label='VLAN group', - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) status = forms.MultipleChoiceField( choices=VLANStatusChoices, diff --git a/netbox/project-static/js/forms.js b/netbox/project-static/js/forms.js index c06eb3045..051b506ed 100644 --- a/netbox/project-static/js/forms.js +++ b/netbox/project-static/js/forms.js @@ -184,6 +184,17 @@ $(document).ready(function() { var param_name = attr.name.split("data-additional-query-param-")[1]; $.each($.parseJSON(attr.value), function(index, value) { + // Referencing the value of another form field + if (value.startsWith('$')) { + let ref_field = $('#id_' + value.slice(1)); + if (ref_field.val() && ref_field.is(":visible")) { + value = ref_field.val(); + } else if (ref_field.attr("required") && ref_field.attr("data-null-option")) { + value = "null"; + } else { + return true; // Skip if ref_field has no value + } + } if (param_name in parameters) { if (Array.isArray(parameters[param_name])) { parameters[param_name].push(value); diff --git a/netbox/tenancy/forms.py b/netbox/tenancy/forms.py index 94df2fc95..5a420f016 100644 --- a/netbox/tenancy/forms.py +++ b/netbox/tenancy/forms.py @@ -119,16 +119,14 @@ class TenancyForm(forms.Form): tenant_group = DynamicModelChoiceField( queryset=TenantGroup.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - 'tenant': 'group_id', - } - ) + null_option='None' ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), - required=False + required=False, + query_params={ + 'group_id': '$tenant_group' + } ) def __init__(self, *args, **kwargs): @@ -148,16 +146,14 @@ class TenancyFilterForm(forms.Form): queryset=TenantGroup.objects.all(), to_field_name='slug', required=False, - null_option='None', - widget=APISelectMultiple( - filter_for={ - 'tenant': 'group' - } - ) + null_option='None' ) tenant = DynamicModelMultipleChoiceField( queryset=Tenant.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'group': '$tenant_group' + } ) diff --git a/netbox/utilities/forms/widgets.py b/netbox/utilities/forms/widgets.py index 91c9656cb..f9eb42663 100644 --- a/netbox/utilities/forms/widgets.py +++ b/netbox/utilities/forms/widgets.py @@ -193,10 +193,13 @@ class APISelect(SelectWithDisabled): :param name: The name of the query param :param value: The value of the query param """ - key = 'data-additional-query-param-{}'.format(name) + key = f'data-additional-query-param-{name}' values = json.loads(self.attrs.get(key, '[]')) - values.append(value) + if type(value) is list: + values.extend(value) + else: + values.append(value) self.attrs[key] = json.dumps(values) diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py index 9bf55e497..c3b243978 100644 --- a/netbox/virtualization/forms.py +++ b/netbox/virtualization/forms.py @@ -171,18 +171,16 @@ class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) group = DynamicModelMultipleChoiceField( queryset=ClusterGroup.objects.all(), @@ -197,38 +195,30 @@ class ClusterAddDevicesForm(BootstrapMixin, forms.Form): region = DynamicModelChoiceField( queryset=Region.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - "site": "region_id", - } - ) + null_option='None' ) site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - widget=APISelect( - filter_for={ - "rack": "site_id", - "devices": "site_id", - } - ) + query_params={ + 'region_id': '$region' + } ) rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, null_option='None', - widget=APISelect( - filter_for={ - "devices": "rack_id" - } - ) + query_params={ + 'site_id': '$site' + } ) devices = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), display_field='display_name', query_params={ - 'cluster_id': 'null' + 'site_id': '$site', + 'rack_id': '$rack', + 'cluster_id': 'null', } ) @@ -274,15 +264,13 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): cluster_group = DynamicModelChoiceField( queryset=ClusterGroup.objects.all(), required=False, - null_option='None', - widget=APISelect( - filter_for={ - "cluster": "group_id", - } - ) + null_option='None' ) cluster = DynamicModelChoiceField( - queryset=Cluster.objects.all() + queryset=Cluster.objects.all(), + query_params={ + 'group_id': '$cluster_group' + } ) role = DynamicModelChoiceField( queryset=DeviceRole.objects.all(), @@ -491,18 +479,16 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil region = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), to_field_name='slug', - required=False, - widget=APISelectMultiple( - filter_for={ - 'site': 'region' - } - ) + required=False ) site = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), to_field_name='slug', required=False, - null_option='None' + null_option='None', + query_params={ + 'region': '$region' + } ) role = DynamicModelMultipleChoiceField( queryset=DeviceRole.objects.filter(vm_role=True), @@ -776,17 +762,15 @@ class VMInterfaceFilterForm(forms.Form): cluster_id = DynamicModelMultipleChoiceField( queryset=Cluster.objects.all(), required=False, - label='Cluster', - widget=APISelectMultiple( - filter_for={ - 'virtual_machine_id': 'cluster_id' - } - ) + label='Cluster' ) virtual_machine_id = DynamicModelMultipleChoiceField( queryset=VirtualMachine.objects.all(), required=False, - label='Virtual machine' + label='Virtual machine', + query_params={ + 'cluster_id': '$cluster_id' + } ) enabled = forms.NullBooleanField( required=False,