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

Closes #21459: Avoid prefetching data for hidden table columns

Jeremy Stretch 1 день назад
Родитель
Сommit
64735d587c

+ 38 - 31
netbox/netbox/tables/tables.py

@@ -52,43 +52,14 @@ class BaseTable(tables.Table):
             'class': 'table table-hover object-list',
             'class': 'table table-hover object-list',
         }
         }
 
 
-    def __init__(self, *args, user=None, **kwargs):
-
+    # TODO: Remove user kwarg in NetBox v4.7
+    def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
 
 
         # Set default empty_text if none was provided
         # Set default empty_text if none was provided
         if self.empty_text is None:
         if self.empty_text is None:
             self.empty_text = _("No {model_name} found").format(model_name=self._meta.model._meta.verbose_name_plural)
             self.empty_text = _("No {model_name} found").format(model_name=self._meta.model._meta.verbose_name_plural)
 
 
-        # Dynamically update the table's QuerySet to ensure related fields are pre-fetched
-        if isinstance(self.data, TableQuerysetData):
-
-            prefetch_fields = []
-            for column in self.columns:
-                if column.visible:
-                    model = getattr(self.Meta, 'model')
-                    accessor = column.accessor
-                    if accessor.startswith('custom_field_data__'):
-                        # Ignore custom field references
-                        continue
-                    prefetch_path = []
-                    for field_name in accessor.split(accessor.SEPARATOR):
-                        try:
-                            field = model._meta.get_field(field_name)
-                        except FieldDoesNotExist:
-                            break
-                        if isinstance(field, (RelatedField, ManyToOneRel)):
-                            # Follow ForeignKeys to the related model
-                            prefetch_path.append(field_name)
-                            model = field.remote_field.model
-                        elif isinstance(field, GenericForeignKey):
-                            # Can't prefetch beyond a GenericForeignKey
-                            prefetch_path.append(field_name)
-                            break
-                    if prefetch_path:
-                        prefetch_fields.append('__'.join(prefetch_path))
-            self.data.data = self.data.data.prefetch_related(*prefetch_fields)
-
     def _get_columns(self, visible=True):
     def _get_columns(self, visible=True):
         columns = []
         columns = []
         for name, column in self.columns.items():
         for name, column in self.columns.items():
@@ -144,6 +115,41 @@ class BaseTable(tables.Table):
             self.sequence.remove('actions')
             self.sequence.remove('actions')
             self.sequence.append('actions')
             self.sequence.append('actions')
 
 
+    def _apply_prefetching(self):
+        """
+        Dynamically update the table's QuerySet to ensure related fields are pre-fetched
+        """
+        if not isinstance(self.data, TableQuerysetData):
+            return
+
+        prefetch_fields = []
+        for column in self.columns:
+            if not column.visible:
+                # Skip hidden columns
+                continue
+            model = getattr(self.Meta, 'model')  # Must be called *after* resolving columns
+            accessor = column.accessor
+            if accessor.startswith('custom_field_data__'):
+                # Ignore custom field references
+                continue
+            prefetch_path = []
+            for field_name in accessor.split(accessor.SEPARATOR):
+                try:
+                    field = model._meta.get_field(field_name)
+                except FieldDoesNotExist:
+                    break
+                if isinstance(field, (RelatedField, ManyToOneRel)):
+                    # Follow ForeignKeys to the related model
+                    prefetch_path.append(field_name)
+                    model = field.remote_field.model
+                elif isinstance(field, GenericForeignKey):
+                    # Can't prefetch beyond a GenericForeignKey
+                    prefetch_path.append(field_name)
+                    break
+            if prefetch_path:
+                prefetch_fields.append('__'.join(prefetch_path))
+        self.data.data = self.data.data.prefetch_related(*prefetch_fields)
+
     def configure(self, request):
     def configure(self, request):
         """
         """
         Configure the table for a specific request context. This performs pagination and records
         Configure the table for a specific request context. This performs pagination and records
@@ -178,6 +184,7 @@ class BaseTable(tables.Table):
             columns = getattr(self.Meta, 'default_columns', self.Meta.fields)
             columns = getattr(self.Meta, 'default_columns', self.Meta.fields)
 
 
         self._set_columns(columns)
         self._set_columns(columns)
+        self._apply_prefetching()
         if ordering is not None:
         if ordering is not None:
             self.order_by = ordering
             self.order_by = ordering
 
 

+ 0 - 1
netbox/netbox/views/generic/feature_views.py

@@ -68,7 +68,6 @@ class ObjectChangeLogView(ConditionalLoginRequiredMixin, View):
         objectchanges_table = ObjectChangeTable(
         objectchanges_table = ObjectChangeTable(
             data=objectchanges,
             data=objectchanges,
             orderable=False,
             orderable=False,
-            user=request.user
         )
         )
         objectchanges_table.configure(request)
         objectchanges_table.configure(request)
 
 

+ 1 - 1
netbox/netbox/views/generic/mixins.py

@@ -92,7 +92,7 @@ class TableMixin:
                 request.user.config.set(f'tables.{table}.columns', tableconfig.columns)
                 request.user.config.set(f'tables.{table}.columns', tableconfig.columns)
                 request.user.config.set(f'tables.{table}.ordering', tableconfig.ordering, commit=True)
                 request.user.config.set(f'tables.{table}.ordering', tableconfig.ordering, commit=True)
 
 
-        table = self.table(data, user=request.user)
+        table = self.table(data)
         if 'pk' in table.base_columns and bulk_actions:
         if 'pk' in table.base_columns and bulk_actions:
             table.columns.show('pk')
             table.columns.show('pk')
         table.configure(request)
         table.configure(request)

+ 1 - 1
netbox/wireless/views.py

@@ -109,7 +109,7 @@ class WirelessLANView(generic.ObjectView):
         attached_interfaces = Interface.objects.restrict(request.user, 'view').filter(
         attached_interfaces = Interface.objects.restrict(request.user, 'view').filter(
             wireless_lans=instance
             wireless_lans=instance
         )
         )
-        interfaces_table = tables.WirelessLANInterfacesTable(attached_interfaces, user=request.user)
+        interfaces_table = tables.WirelessLANInterfacesTable(attached_interfaces)
         interfaces_table.configure(request)
         interfaces_table.configure(request)
 
 
         return {
         return {