Просмотр исходного кода

Move null_option to DynamicModelChoiceMixin

Jeremy Stretch 5 лет назад
Родитель
Сommit
8a8b4e728a

+ 11 - 29
netbox/dcim/forms.py

@@ -672,9 +672,7 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
         ),
         ),
         required=False,
         required=False,
         label='Rack group',
         label='Rack group',
-        widget=APISelectMultiple(
-            null_option=True
-        )
+        null_option='None'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=RackStatusChoices,
         choices=RackStatusChoices,
@@ -685,9 +683,7 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
         queryset=RackRole.objects.all(),
         queryset=RackRole.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -853,9 +849,7 @@ class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm):
         queryset=RackGroup.objects.prefetch_related('site'),
         queryset=RackGroup.objects.prefetch_related('site'),
         required=False,
         required=False,
         label='Rack group',
         label='Rack group',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -2124,9 +2118,7 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         required=False,
         required=False,
         label='Rack',
         label='Rack',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     role = DynamicModelMultipleChoiceField(
     role = DynamicModelMultipleChoiceField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
@@ -2155,9 +2147,7 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=DeviceStatusChoices,
         choices=DeviceStatusChoices,
@@ -3879,8 +3869,8 @@ class CableFilterForm(BootstrapMixin, forms.Form):
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         required=False,
         required=False,
         label='Rack',
         label='Rack',
+        null_option='None',
         widget=APISelectMultiple(
         widget=APISelectMultiple(
-            null_option=True,
             filter_for={
             filter_for={
                 'device_id': 'rack_id',
                 'device_id': 'rack_id',
             }
             }
@@ -4208,8 +4198,8 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
+        null_option='None',
         widget=APISelectMultiple(
         widget=APISelectMultiple(
-            null_option=True,
             filter_for={
             filter_for={
                 'tenant': 'group'
                 'tenant': 'group'
             }
             }
@@ -4219,9 +4209,7 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -4336,9 +4324,7 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=RackGroup.objects.all(),
         queryset=RackGroup.objects.all(),
         required=False,
         required=False,
         label='Rack group (ID)',
         label='Rack group (ID)',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -4555,17 +4541,13 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=PowerPanel.objects.all(),
         queryset=PowerPanel.objects.all(),
         required=False,
         required=False,
         label='Power panel',
         label='Power panel',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     rack_id = DynamicModelMultipleChoiceField(
     rack_id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         required=False,
         required=False,
         label='Rack',
         label='Rack',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=PowerFeedStatusChoices,
         choices=PowerFeedStatusChoices,

+ 8 - 24
netbox/ipam/forms.py

@@ -464,9 +464,7 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
         label='VRF',
         label='VRF',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='Global'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=PrefixStatusChoices,
         choices=PrefixStatusChoices,
@@ -487,17 +485,13 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     role = DynamicModelMultipleChoiceField(
     role = DynamicModelMultipleChoiceField(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     is_pool = forms.NullBooleanField(
     is_pool = forms.NullBooleanField(
         required=False,
         required=False,
@@ -910,9 +904,7 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
         label='VRF',
         label='VRF',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='Global'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=IPAddressStatusChoices,
         choices=IPAddressStatusChoices,
@@ -981,9 +973,7 @@ class VLANGroupFilterForm(BootstrapMixin, forms.Form):
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
 
 
 
 
@@ -1147,17 +1137,13 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
         required=False,
         required=False,
         label='VLAN group',
         label='VLAN group',
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=VLANStatusChoices,
         choices=VLANStatusChoices,
@@ -1168,9 +1154,7 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 

+ 1 - 1
netbox/project-static/js/forms.js

@@ -247,7 +247,7 @@ $(document).ready(function() {
                 if (element.getAttribute('data-null-option') && data.previous === null) {
                 if (element.getAttribute('data-null-option') && data.previous === null) {
                     results.unshift({
                     results.unshift({
                         id: 'null',
                         id: 'null',
-                        text: 'None'
+                        text: element.getAttribute('data-null-option')
                     });
                     });
                 }
                 }
 
 

+ 3 - 7
netbox/tenancy/forms.py

@@ -106,9 +106,7 @@ class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -152,8 +150,8 @@ class TenancyFilterForm(forms.Form):
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
+        null_option='None',
         widget=APISelectMultiple(
         widget=APISelectMultiple(
-            null_option=True,
             filter_for={
             filter_for={
                 'tenant': 'group'
                 'tenant': 'group'
             }
             }
@@ -163,7 +161,5 @@ class TenancyFilterForm(forms.Form):
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )

+ 11 - 1
netbox/utilities/forms/fields.py

@@ -245,12 +245,18 @@ class TagFilterField(forms.MultipleChoiceField):
 
 
 
 
 class DynamicModelChoiceMixin:
 class DynamicModelChoiceMixin:
+    """
+    :param display_field: The name of the attribute of an API response object to display in the selection list
+    :param query_params: A dictionary of additional key/value pairs to attach to the API request
+    :param null_option: The string used to represent a null selection (if any)
+    """
     filter = django_filters.ModelChoiceFilter
     filter = django_filters.ModelChoiceFilter
     widget = widgets.APISelect
     widget = widgets.APISelect
 
 
-    def __init__(self, *args, display_field='name', query_params=None, **kwargs):
+    def __init__(self, *args, display_field='name', query_params=None, null_option=None, **kwargs):
         self.display_field = display_field
         self.display_field = display_field
         self.query_params = query_params or {}
         self.query_params = query_params or {}
+        self.null_option = null_option
 
 
         # to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
         # to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
         # by widget_attrs()
         # by widget_attrs()
@@ -267,6 +273,10 @@ class DynamicModelChoiceMixin:
         if self.to_field_name:
         if self.to_field_name:
             attrs['value-field'] = self.to_field_name
             attrs['value-field'] = self.to_field_name
 
 
+        # Set the string used to represent a null option
+        if self.null_option is not None:
+            attrs['data-null-option'] = self.null_option
+
         # Attach any static query parameters
         # Attach any static query parameters
         for key, value in self.query_params.items():
         for key, value in self.query_params.items():
             widget.add_additional_query_param(key, value)
             widget.add_additional_query_param(key, value)

+ 0 - 4
netbox/utilities/forms/widgets.py

@@ -146,7 +146,6 @@ class APISelect(SelectWithDisabled):
         name of the filter-for field (child field) and the value is the name of the query param filter.
         name of the filter-for field (child field) and the value is the name of the query param filter.
     :param additional_query_params: Optional) A dict of query params to append to the API request. The key is the
     :param additional_query_params: Optional) A dict of query params to append to the API request. The key is the
         name of the query param and the value if the query param's value.
         name of the query param and the value if the query param's value.
-    :param null_option: If true, include the static null option in the selection list.
     """
     """
     def __init__(
     def __init__(
         self,
         self,
@@ -155,7 +154,6 @@ class APISelect(SelectWithDisabled):
         disabled_indicator=None,
         disabled_indicator=None,
         filter_for=None,
         filter_for=None,
         additional_query_params=None,
         additional_query_params=None,
-        null_option=False,
         full=False,
         full=False,
         *args,
         *args,
         **kwargs
         **kwargs
@@ -178,8 +176,6 @@ class APISelect(SelectWithDisabled):
         if additional_query_params:
         if additional_query_params:
             for key, value in additional_query_params.items():
             for key, value in additional_query_params.items():
                 self.add_additional_query_param(key, value)
                 self.add_additional_query_param(key, value)
-        if null_option:
-            self.attrs['data-null-option'] = 1
 
 
     def add_filter_for(self, name, value):
     def add_filter_for(self, name, value):
         """
         """

+ 8 - 20
netbox/virtualization/forms.py

@@ -182,17 +182,13 @@ class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     group = DynamicModelMultipleChoiceField(
     group = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -485,17 +481,13 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     cluster_type = DynamicModelMultipleChoiceField(
     cluster_type = DynamicModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     cluster_id = DynamicModelMultipleChoiceField(
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
@@ -516,18 +508,16 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     role = DynamicModelMultipleChoiceField(
     role = DynamicModelMultipleChoiceField(
         queryset=DeviceRole.objects.filter(vm_role=True),
         queryset=DeviceRole.objects.filter(vm_role=True),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
+        null_option='None',
         query_params={
         query_params={
             'vm_role': "True"
             'vm_role': "True"
-        },
-        widget=APISelectMultiple(null_option=True)
+        }
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=VirtualMachineStatusChoices,
         choices=VirtualMachineStatusChoices,
@@ -538,9 +528,7 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
         required=False,
         required=False,
-        widget=APISelectMultiple(
-            null_option=True,
-        )
+        null_option='None'
     )
     )
     mac_address = forms.CharField(
     mac_address = forms.CharField(
         required=False,
         required=False,