diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 3ecc56533..dae5b5715 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2241,10 +2241,11 @@ class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): queryset=Site.objects.all(), label='Site', required=False, - widget=forms.Select( - attrs={ - 'data-filter-for-termination_b_rack': 'site_id', - 'data-filter-for-termination_b_device': 'site_id', + widget=APISelect( + api_url='/api/dcim/sites/', + filter_for={ + 'termination_b_rack': 'site_id', + 'termination_b_device': 'site_id', } ) ) @@ -2257,8 +2258,10 @@ class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): required=False, widget=APISelect( api_url='/api/dcim/racks/', + filter_for={ + 'termination_b_device': 'rack_id', + }, attrs={ - 'data-filter-for-termination_b_device': 'rack_id', 'nullable': 'true', } ) @@ -2270,23 +2273,15 @@ class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): ('rack', 'termination_b_rack'), ), label='Device', + required=False, widget=APISelect( api_url='/api/dcim/devices/', display_field='display_name', - attrs={ - 'data-filter-for-termination_b_id': 'device_id', + filter_for={ + 'termination_b_id': 'device_id', } ) ) - livesearch = forms.CharField( - required=False, - label='Device', - widget=Livesearch( - query_key='q', - query_url='dcim-api:device-list', - field_to_update='termination_b_device' - ) - ) termination_b_type = forms.ModelChoiceField( queryset=ContentType.objects.all(), label='Type', diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index 1b9369451..34d737317 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -238,6 +238,8 @@ class APISelect(SelectWithDisabled): :param api_url: API URL :param display_field: (Optional) Field to display for child in selection list. Defaults to `name`. :param disabled_indicator: (Optional) Mark option as disabled if this field equates true. + :param filter_for: (Optional) A dict of chained form fields for which this field is a filter. The key is the + name of the filter-for field (child field) and the value is the name of the query param filter. :param conditional_query_params: (Optional) A dict of URL query params to append to the URL if the condition is met. The condition is the dict key and is specified in the form `__`. If the provided field value is selected for the given field, the URL query param will be appended to @@ -252,6 +254,7 @@ class APISelect(SelectWithDisabled): api_url, display_field=None, disabled_indicator=None, + filter_for=None, conditional_query_params=None, additional_query_params=None, *args, @@ -266,6 +269,9 @@ class APISelect(SelectWithDisabled): self.attrs['display-field'] = display_field if disabled_indicator: self.attrs['disabled-indicator'] = disabled_indicator + if filter_for: + for key, value in filter_for.items(): + self.add_filter_for(key, value) if conditional_query_params: for key, value in conditional_query_params.items(): self.add_conditional_query_param(key, value) @@ -273,6 +279,15 @@ class APISelect(SelectWithDisabled): for key, value in additional_query_params.items(): self.add_additional_query_param(key, value) + def add_filter_for(self, name, value): + """ + Add details for an additional query param in the form of a data-filter-for-* attribute. + + :param name: The name of the query param + :param value: The value of the query param + """ + self.attrs['data-filter-for-{}'.format(name)] = value + def add_additional_query_param(self, name, value): """ Add details for an additional query param in the form of a data-* attribute.