Pārlūkot izejas kodu

Fixes #21160: Fix performance issue rendering FilterSet forms w/ large choicesets (#21200)

Arthur Hanson 4 nedēļas atpakaļ
vecāks
revīzija
52a2b934a0
1 mainītis faili ar 30 papildinājumiem un 0 dzēšanām
  1. 30 0
      netbox/utilities/forms/widgets/modifiers.py

+ 30 - 0
netbox/utilities/forms/widgets/modifiers.py

@@ -1,6 +1,8 @@
 from django import forms
 from django.utils.translation import gettext_lazy as _
 
+from utilities.forms.widgets.apiselect import APISelect, APISelectMultiple
+
 __all__ = (
     'FilterModifierWidget',
     'MODIFIER_EMPTY_FALSE',
@@ -94,9 +96,37 @@ class FilterModifierWidget(forms.Widget):
         # to the original widget before rendering
         self.original_widget.attrs.update(self.attrs)
 
+        # For APISelect/APISelectMultiple widgets, temporarily clear choices to prevent queryset evaluation
+        original_choices = None
+        if isinstance(self.original_widget, (APISelect, APISelectMultiple)):
+            original_choices = self.original_widget.choices
+
+            # Only keep selected choices to preserve current selection in HTML
+            if value:
+                values = value if isinstance(value, (list, tuple)) else [value]
+
+                if hasattr(original_choices, 'queryset'):
+                    queryset = original_choices.queryset
+                    selected_objects = queryset.filter(pk__in=values)
+                    # Build minimal choice list with just the selected values
+                    self.original_widget.choices = [
+                        (obj.pk, str(obj)) for obj in selected_objects
+                    ]
+                else:
+                    self.original_widget.choices = [
+                        choice for choice in original_choices if choice[0] in values
+                    ]
+            else:
+                # No selection - render empty select element
+                self.original_widget.choices = []
+
         # Get context from the original widget
         original_context = self.original_widget.get_context(name, value, attrs)
 
+        # Restore original choices if we modified them
+        if original_choices is not None:
+            self.original_widget.choices = original_choices
+
         # Build our wrapper context
         context = super().get_context(name, value, attrs)
         context['widget']['original_widget'] = original_context['widget']