diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index febeeaa12..49fa1173d 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -716,9 +716,7 @@ class RackElevationFilterForm(RackFilterForm): queryset=Rack.objects.all(), label='Rack', required=False, - widget=APISelectMultiple( - display_field='display_name', - ) + display_field='display_name' ) def __init__(self, *args, **kwargs): @@ -1048,9 +1046,7 @@ class ComponentTemplateCreateForm(ComponentForm): ) device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), - widget=APISelect( - display_field='model' - ) + display_field='model' ) description = forms.CharField( required=False @@ -1739,9 +1735,7 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, - widget=APISelect( - display_field='display_name' - ) + display_field='display_name' ) position = forms.TypedChoiceField( required=False, @@ -1764,9 +1758,7 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): ) device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), - widget=APISelect( - display_field='model' - ) + display_field='model' ) device_role = DynamicModelChoiceField( queryset=DeviceRole.objects.all() @@ -2078,9 +2070,7 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF device_type = DynamicModelChoiceField( queryset=DeviceType.objects.all(), required=False, - widget=APISelect( - display_field="model", - ) + display_field='model' ) device_role = DynamicModelChoiceField( queryset=DeviceRole.objects.all(), @@ -2184,9 +2174,7 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt queryset=DeviceType.objects.all(), required=False, label='Model', - widget=APISelectMultiple( - display_field="model", - ) + display_field='model' ) platform = DynamicModelMultipleChoiceField( queryset=Platform.objects.all(), @@ -2715,8 +2703,8 @@ class InterfaceForm(InterfaceCommonForm, BootstrapMixin, forms.ModelForm): queryset=VLAN.objects.all(), required=False, label='Untagged VLAN', + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -2727,8 +2715,8 @@ class InterfaceForm(InterfaceCommonForm, BootstrapMixin, forms.ModelForm): queryset=VLAN.objects.all(), required=False, label='Tagged VLANs', + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -2816,8 +2804,8 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm): untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -2827,8 +2815,8 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -2885,8 +2873,8 @@ class InterfaceBulkEditForm( untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -2896,8 +2884,8 @@ class InterfaceBulkEditForm( tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -3514,8 +3502,8 @@ class ConnectCableToDeviceForm(BootstrapMixin, forms.ModelForm): queryset=Device.objects.all(), label='Device', required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', filter_for={ 'termination_b_id': 'device_id', } @@ -3632,8 +3620,8 @@ class ConnectCableToCircuitTerminationForm(BootstrapMixin, forms.ModelForm): termination_b_circuit = DynamicModelChoiceField( queryset=Circuit.objects.all(), label='Circuit', + display_field='cid', widget=APISelect( - display_field='cid', filter_for={ 'termination_b_id': 'circuit_id', } @@ -3662,8 +3650,8 @@ class ConnectCableToPowerFeedForm(BootstrapMixin, forms.ModelForm): queryset=Site.objects.all(), label='Site', required=False, + display_field='cid', widget=APISelect( - display_field='cid', filter_for={ 'termination_b_rackgroup': 'site_id', 'termination_b_powerpanel': 'site_id', @@ -3674,8 +3662,8 @@ class ConnectCableToPowerFeedForm(BootstrapMixin, forms.ModelForm): queryset=RackGroup.objects.all(), label='Rack Group', required=False, + display_field='cid', widget=APISelect( - display_field='cid', filter_for={ 'termination_b_powerpanel': 'rackgroup_id', } @@ -4199,8 +4187,8 @@ class VCMemberSelectForm(BootstrapMixin, forms.Form): queryset=Device.objects.filter( virtual_chassis__isnull=True ), + display_field='display_name', widget=APISelect( - display_field='display_name', disabled_indicator='virtual_chassis' ) ) diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index a565375c5..30279e012 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -413,9 +413,9 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form): user = DynamicModelMultipleChoiceField( queryset=User.objects.all(), required=False, + display_field='username', widget=APISelectMultiple( api_url='/api/users/users/', - display_field='username' ) ) changed_object_type = forms.ModelChoiceField( diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 15c69c504..aad3eaade 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -287,9 +287,7 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): queryset=VLAN.objects.all(), required=False, label='VLAN', - widget=APISelect( - display_field='display_name' - ) + display_field='display_name' ) role = DynamicModelChoiceField( queryset=Role.objects.all(), @@ -569,8 +567,8 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel queryset=Rack.objects.all(), required=False, label='Rack', + display_field='display_name', widget=APISelect( - display_field='display_name', filter_for={ 'nat_device': 'rack_id' }, @@ -583,8 +581,8 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel queryset=Device.objects.all(), required=False, label='Device', + display_field='display_name', widget=APISelect( - display_field='display_name', filter_for={ 'nat_inside': 'device_id' } @@ -604,9 +602,7 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel queryset=IPAddress.objects.all(), required=False, label='IP Address', - widget=APISelect( - display_field='address' - ) + display_field='address' ) primary_for_parent = forms.BooleanField( required=False, diff --git a/netbox/utilities/forms/fields.py b/netbox/utilities/forms/fields.py index b4948a419..fbcc285a9 100644 --- a/netbox/utilities/forms/fields.py +++ b/netbox/utilities/forms/fields.py @@ -11,6 +11,7 @@ from django.db.models import Count from django.forms import BoundField from django.urls import reverse +from utilities.api import get_serializer_for_model from utilities.choices import unpack_grouped_choices from utilities.validators import EnhancedURLValidator from . import widgets @@ -247,6 +248,16 @@ class DynamicModelChoiceMixin: filter = django_filters.ModelChoiceFilter widget = widgets.APISelect + def __init__(self, *args, display_field='name', **kwargs): + self.display_field = display_field + + super().__init__(*args, **kwargs) + + def widget_attrs(self, widget): + return { + 'display-field': self.display_field + } + def get_bound_field(self, form, field_name): bound_field = BoundField(form, self, field_name) diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py index d32b08ffa..b1a2de6aa 100644 --- a/netbox/virtualization/forms.py +++ b/netbox/virtualization/forms.py @@ -240,8 +240,8 @@ class ClusterAddDevicesForm(BootstrapMixin, forms.Form): ) devices = DynamicModelMultipleChoiceField( queryset=Device.objects.filter(cluster__isnull=True), + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', disabled_indicator='cluster' ) ) @@ -575,8 +575,8 @@ class VMInterfaceForm(BootstrapMixin, forms.ModelForm): untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -586,8 +586,8 @@ class VMInterfaceForm(BootstrapMixin, forms.ModelForm): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -679,8 +679,8 @@ class VMInterfaceCreateForm(BootstrapMixin, forms.Form): untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -690,8 +690,8 @@ class VMInterfaceCreateForm(BootstrapMixin, forms.Form): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -773,8 +773,8 @@ class VMInterfaceBulkEditForm(BootstrapMixin, BulkEditForm): untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelect( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null', @@ -784,8 +784,8 @@ class VMInterfaceBulkEditForm(BootstrapMixin, BulkEditForm): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, + display_field='display_name', widget=APISelectMultiple( - display_field='display_name', full=True, additional_query_params={ 'site_id': 'null',