mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Add support for custom fields in tables (#5460)
* Add support for custom fields in tables * Fix empty list displays as none Co-authored-by: TomGrozev <TomGrozev@users.noreply.github.com> Co-authored-by: Jeremy Stretch <jeremy@netverity.dev>
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
import django_tables2 as tables
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import Func, F, Value
|
||||
from django.db.models.fields.related import RelatedField
|
||||
from django.urls import reverse
|
||||
from django.utils.html import strip_tags
|
||||
@ -9,6 +11,7 @@ from django.utils.safestring import mark_safe
|
||||
from django_tables2 import RequestConfig
|
||||
from django_tables2.data import TableQuerysetData
|
||||
|
||||
from .models import CustomField
|
||||
from .paginator import EnhancedPaginator, get_paginate_count
|
||||
|
||||
|
||||
@ -30,12 +33,25 @@ class BaseTable(tables.Table):
|
||||
|
||||
:param user: Personalize table display for the given user (optional). Has no effect if AnonymousUser is passed.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
attrs = {
|
||||
'class': 'table table-hover table-headings',
|
||||
}
|
||||
|
||||
def __init__(self, *args, user=None, **kwargs):
|
||||
# Add custom field columns
|
||||
obj_type = ContentType.objects.get_for_model(self._meta.model)
|
||||
custom_fields = {}
|
||||
|
||||
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())
|
||||
|
||||
# Init table
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Set default empty_text if none was provided
|
||||
@ -73,6 +89,12 @@ class BaseTable(tables.Table):
|
||||
|
||||
# Dynamically update the table's QuerySet to ensure related fields are pre-fetched
|
||||
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 = []
|
||||
for column in self.columns:
|
||||
if column.visible:
|
||||
@ -316,6 +338,28 @@ class TagColumn(tables.TemplateColumn):
|
||||
return ",".join([tag.name for tag in value.all()])
|
||||
|
||||
|
||||
class CustomFieldColumn(tables.Column):
|
||||
"""
|
||||
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">—</span>'
|
||||
elif value:
|
||||
template = value
|
||||
else:
|
||||
return self.default
|
||||
return mark_safe(template)
|
||||
|
||||
def value(self, value):
|
||||
return value
|
||||
|
||||
|
||||
class MPTTColumn(tables.TemplateColumn):
|
||||
"""
|
||||
Display a nested hierarchy for MPTT-enabled models.
|
||||
@ -362,3 +406,4 @@ def paginate_table(table, request):
|
||||
'per_page': get_paginate_count(request)
|
||||
}
|
||||
RequestConfig(request, paginate).configure(table)
|
||||
|
||||
|
Reference in New Issue
Block a user