Add support for custom fields in tables

This commit is contained in:
TomGrozev 2020-12-15 15:05:48 +11:00
parent c1e56a3717
commit a8cdbcfd01

View File

@ -1,12 +1,15 @@
import django_tables2 as tables import django_tables2 as tables
from django.contrib.auth.models import AnonymousUser 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.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.safestring import mark_safe from django.utils.safestring import mark_safe
from django_tables2.data import TableQuerysetData from django_tables2.data import TableQuerysetData
from extras.models import CustomField
class BaseTable(tables.Table): class BaseTable(tables.Table):
""" """
@ -14,12 +17,25 @@ class BaseTable(tables.Table):
:param user: Personalize table display for the given user (optional). Has no effect if AnonymousUser is passed. :param user: Personalize table display for the given user (optional). Has no effect if AnonymousUser is passed.
""" """
class Meta: class Meta:
attrs = { attrs = {
'class': 'table table-hover table-headings', 'class': 'table table-hover table-headings',
} }
def __init__(self, *args, user=None, **kwargs): 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) super().__init__(*args, **kwargs)
# Set default empty_text if none was provided # Set default empty_text if none was provided
@ -57,6 +73,12 @@ 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:
if column.visible: if column.visible:
@ -267,3 +289,21 @@ class TagColumn(tables.TemplateColumn):
template_code=self.template_code, template_code=self.template_code,
extra_context={'url_name': url_name} extra_context={'url_name': url_name}
) )
class CustomFieldColumn(tables.Column):
"""
Display custom fields in the appropriate format.
"""
def render(self, record, bound_column, value):
if value:
if isinstance(value, list):
template = ''
for v in value:
template += f'<span class="label label-default">{v}</span> '
else:
template = value
return mark_safe(template)
return self.default