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

Clean up custom field column implementation

Jeremy Stretch 4 лет назад
Родитель
Сommit
7885ec5511
2 измененных файлов с 16 добавлено и 32 удалено
  1. 1 0
      docs/release-notes/version-2.11.md
  2. 15 32
      netbox/utilities/tables.py

+ 1 - 0
docs/release-notes/version-2.11.md

@@ -85,6 +85,7 @@ A new Cloud model has been introduced to represent the boundary of a network tha
 ### Enhancements
 ### Enhancements
 
 
 * [#4833](https://github.com/netbox-community/netbox/issues/4833) - Allow assigning config contexts by device type
 * [#4833](https://github.com/netbox-community/netbox/issues/4833) - Allow assigning config contexts by device type
+* [#5344](https://github.com/netbox-community/netbox/issues/5344) - Add support for custom fields in tables
 * [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
 * [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
 * [#5375](https://github.com/netbox-community/netbox/issues/5375) - Add `speed` attribute to console port models
 * [#5375](https://github.com/netbox-community/netbox/issues/5375) - Add `speed` attribute to console port models
 * [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
 * [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models

+ 15 - 32
netbox/utilities/tables.py

@@ -3,15 +3,15 @@ from django.contrib.auth.models import AnonymousUser
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import FieldDoesNotExist
 from django.core.exceptions import FieldDoesNotExist
-from django.db.models import Func, F, Value
 from django.db.models.fields.related import RelatedField
 from django.db.models.fields.related import RelatedField
 from django.urls import reverse
 from django.urls import reverse
 from django.utils.html import strip_tags
 from django.utils.html import strip_tags
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
 from django_tables2 import RequestConfig
 from django_tables2 import RequestConfig
 from django_tables2.data import TableQuerysetData
 from django_tables2.data import TableQuerysetData
+from django_tables2.utils import Accessor
 
 
-from .models import CustomField
+from extras.models import CustomField
 from .paginator import EnhancedPaginator, get_paginate_count
 from .paginator import EnhancedPaginator, get_paginate_count
 
 
 
 
@@ -42,21 +42,14 @@ class BaseTable(tables.Table):
     def __init__(self, *args, user=None, **kwargs):
     def __init__(self, *args, user=None, **kwargs):
         # Add custom field columns
         # Add custom field columns
         obj_type = ContentType.objects.get_for_model(self._meta.model)
         obj_type = ContentType.objects.get_for_model(self._meta.model)
-        custom_fields = {}
-
         for cf in CustomField.objects.filter(content_types=obj_type):
         for cf in CustomField.objects.filter(content_types=obj_type):
-            name = 'cf_{}'.format(cf.name)
-            label = cf.label if cf.label != '' else cf.name
-            self.base_columns[name] = CustomFieldColumn(verbose_name=label)
-            custom_fields[name] = cf
-        self._meta.fields += tuple(custom_fields.keys())
+            self.base_columns[f'cf_{cf.name}'] = CustomFieldColumn(cf)
 
 
-        # Init table
         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 {} found'.format(self._meta.model._meta.verbose_name_plural)
+            self.empty_text = f"No {self._meta.model._meta.verbose_name_plural} found"
 
 
         # Hide non-default columns
         # Hide non-default columns
         default_columns = getattr(self.Meta, 'default_columns', list())
         default_columns = getattr(self.Meta, 'default_columns', list())
@@ -89,11 +82,6 @@ class BaseTable(tables.Table):
 
 
         # Dynamically update the table's QuerySet to ensure related fields are pre-fetched
         # Dynamically update the table's QuerySet to ensure related fields are pre-fetched
         if isinstance(self.data, TableQuerysetData):
         if isinstance(self.data, TableQuerysetData):
-            # Extract custom field values
-            cf_fields = {}
-            for key, cf in custom_fields.items():
-                cf_fields[key] = Func(F('custom_field_data'), Value(cf.name), function='jsonb_extract_path_text')
-            self.data.data = self.data.data.annotate(**cf_fields)
 
 
             prefetch_fields = []
             prefetch_fields = []
             for column in self.columns:
             for column in self.columns:
@@ -342,22 +330,18 @@ class CustomFieldColumn(tables.Column):
     """
     """
     Display custom fields in the appropriate format.
     Display custom fields in the appropriate format.
     """
     """
-    def render(self, record, bound_column, value):
-        if isinstance(value, list):
-            if len(value):
-                template = ''
-                for v in value:
-                    template += f'<span class="label label-default">{v}</span> '
-            else:
-                template = '<span class="text-muted">&mdash;</span>'
-        elif value:
-            template = value
-        else:
-            return self.default
-        return mark_safe(template)
+    def __init__(self, customfield, *args, **kwargs):
+        self.customfield = customfield
+        kwargs['accessor'] = Accessor(f'custom_field_data__{customfield.name}')
+        if 'verbose_name' not in kwargs:
+            kwargs['verbose_name'] = customfield.label or customfield.name
 
 
-    def value(self, value):
-        return value
+        super().__init__(*args, **kwargs)
+
+    def render(self, value):
+        if isinstance(value, list):
+            return ', '.join(v for v in value)
+        return value or self.default
 
 
 
 
 class MPTTColumn(tables.TemplateColumn):
 class MPTTColumn(tables.TemplateColumn):
@@ -406,4 +390,3 @@ def paginate_table(table, request):
         'per_page': get_paginate_count(request)
         'per_page': get_paginate_count(request)
     }
     }
     RequestConfig(request, paginate).configure(table)
     RequestConfig(request, paginate).configure(table)
-