Kaynağa Gözat

Add initial_params to DynamicModelChoiceMixin

Jeremy Stretch 5 yıl önce
ebeveyn
işleme
1f0b1dd10e
2 değiştirilmiş dosya ile 28 ekleme ve 26 silme
  1. 15 24
      netbox/dcim/forms.py
  2. 13 2
      netbox/utilities/forms/fields.py

+ 15 - 24
netbox/dcim/forms.py

@@ -1672,7 +1672,10 @@ class PlatformCSVForm(CSVModelForm):
 class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
 class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        required=False
+        required=False,
+        initial_params={
+            'sites': '$site'
+        }
     )
     )
     site = DynamicModelChoiceField(
     site = DynamicModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
@@ -1686,6 +1689,9 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
         display_field='display_name',
         display_field='display_name',
         query_params={
         query_params={
             'site_id': '$site'
             'site_id': '$site'
+        },
+        initial_params={
+            'racks': '$rack'
         }
         }
     )
     )
     rack = DynamicModelChoiceField(
     rack = DynamicModelChoiceField(
@@ -1711,7 +1717,10 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     )
     )
     manufacturer = DynamicModelChoiceField(
     manufacturer = DynamicModelChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
-        required=False
+        required=False,
+        initial_params={
+            'device_types': '$device_type'
+        }
     )
     )
     device_type = DynamicModelChoiceField(
     device_type = DynamicModelChoiceField(
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),
@@ -1733,7 +1742,10 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     cluster_group = DynamicModelChoiceField(
     cluster_group = DynamicModelChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        initial_params={
+            'clusters': '$cluster'
+        }
     )
     )
     cluster = DynamicModelChoiceField(
     cluster = DynamicModelChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
@@ -1772,27 +1784,6 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
         }
         }
 
 
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
-
-        # Initialize helper selectors
-        instance = kwargs.get('instance')
-        if 'initial' not in kwargs:
-            kwargs['initial'] = {}
-        # Using hasattr() instead of "is not None" to avoid RelatedObjectDoesNotExist on required field
-        if instance and hasattr(instance, 'device_type'):
-            kwargs['initial']['manufacturer'] = instance.device_type.manufacturer
-        if instance and instance.cluster is not None:
-            kwargs['initial']['cluster_group'] = instance.cluster.group
-
-        if 'device_type' in kwargs['initial'] and 'manufacturer' not in kwargs['initial']:
-            device_type_id = kwargs['initial']['device_type']
-            manufacturer_id = DeviceType.objects.filter(pk=device_type_id).values_list('manufacturer__pk', flat=True).first()
-            kwargs['initial']['manufacturer'] = manufacturer_id
-
-        if 'cluster' in kwargs['initial'] and 'cluster_group' not in kwargs['initial']:
-            cluster_id = kwargs['initial']['cluster']
-            cluster_group_id = Cluster.objects.filter(pk=cluster_id).values_list('group__pk', flat=True).first()
-            kwargs['initial']['cluster_group'] = cluster_group_id
-
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
 
 
         if self.instance.pk:
         if self.instance.pk:

+ 13 - 2
netbox/utilities/forms/fields.py

@@ -248,6 +248,7 @@ class DynamicModelChoiceMixin:
     """
     """
     :param display_field: The name of the attribute of an API response object to display in the selection list
     :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 query_params: A dictionary of additional key/value pairs to attach to the API request
+    :param initial_params: A dictionary of child field references to use for selecting a parent field's initial value
     :param null_option: The string used to represent a null selection (if any)
     :param null_option: The string used to represent a null selection (if any)
     :param disabled_indicator: The name of the field which, if populated, will disable selection of the
     :param disabled_indicator: The name of the field which, if populated, will disable selection of the
         choice (optional)
         choice (optional)
@@ -256,10 +257,11 @@ class DynamicModelChoiceMixin:
     filter = django_filters.ModelChoiceFilter
     filter = django_filters.ModelChoiceFilter
     widget = widgets.APISelect
     widget = widgets.APISelect
 
 
-    def __init__(self, display_field='name', query_params=None, null_option=None, disabled_indicator=None,
-                 brief_mode=True, *args, **kwargs):
+    def __init__(self, display_field='name', query_params=None, initial_params=None, null_option=None,
+                 disabled_indicator=None, brief_mode=True, *args, **kwargs):
         self.display_field = display_field
         self.display_field = display_field
         self.query_params = query_params or {}
         self.query_params = query_params or {}
+        self.initial_params = initial_params or {}
         self.null_option = null_option
         self.null_option = null_option
         self.disabled_indicator = disabled_indicator
         self.disabled_indicator = disabled_indicator
         self.brief_mode = brief_mode
         self.brief_mode = brief_mode
@@ -300,6 +302,15 @@ class DynamicModelChoiceMixin:
     def get_bound_field(self, form, field_name):
     def get_bound_field(self, form, field_name):
         bound_field = BoundField(form, self, field_name)
         bound_field = BoundField(form, self, field_name)
 
 
+        # Set initial value based on prescribed child fields (if not already set)
+        if not self.initial and self.initial_params:
+            filter_kwargs = {}
+            for kwarg, child_field in self.initial_params.items():
+                value = form.initial.get(child_field.lstrip('$'))
+                if value:
+                    filter_kwargs[kwarg] = value
+            self.initial = self.queryset.filter(**filter_kwargs).first()
+
         # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
         # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
         # will be populated on-demand via the APISelect widget.
         # will be populated on-demand via the APISelect widget.
         data = bound_field.value()
         data = bound_field.value()