1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Merge branch 'feature' of https://github.com/netbox-community/netbox into feature

# Conflicts:
#	netbox/dcim/tables/template_code.py
#	netbox/netbox/views/__init__.py
#	netbox/project-static/css/base.css
#	netbox/templates/base.html
#	netbox/templates/circuits/circuit.html
#	netbox/templates/circuits/circuittermination_edit.html
#	netbox/templates/circuits/inc/circuit_termination.html
#	netbox/templates/circuits/provider.html
#	netbox/templates/dcim/device.html
#	netbox/templates/dcim/device/base.html
#	netbox/templates/dcim/device_component.html
#	netbox/templates/dcim/devicetype.html
#	netbox/templates/dcim/inc/device_napalm_tabs.html
#	netbox/templates/dcim/rack.html
#	netbox/templates/dcim/site.html
#	netbox/templates/dcim/virtualchassis.html
#	netbox/templates/extras/configcontext.html
#	netbox/templates/extras/object_journal.html
#	netbox/templates/extras/tag.html
#	netbox/templates/generic/object.html
#	netbox/templates/generic/object_list.html
#	netbox/templates/home.html
#	netbox/templates/inc/nav_menu.html
#	netbox/templates/ipam/aggregate.html
#	netbox/templates/ipam/ipaddress.html
#	netbox/templates/ipam/prefix.html
#	netbox/templates/ipam/vlan.html
#	netbox/templates/ipam/vlangroup_edit.html
#	netbox/templates/ipam/vlangroup_vlans.html
#	netbox/templates/secrets/secret.html
#	netbox/templates/tenancy/tenant.html
#	netbox/templates/users/api_tokens.html
#	netbox/templates/virtualization/cluster.html
#	netbox/templates/virtualization/vminterface_edit.html
#	netbox/utilities/forms/fields.py
#	netbox/utilities/templates/buttons/export.html
This commit is contained in:
checktheroads
2021-04-14 11:30:15 -07:00
256 changed files with 5928 additions and 2111 deletions

View File

@@ -1,11 +1,31 @@
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.fields.related import RelatedField
from django.urls import reverse
from django.utils.html import strip_tags
from django.utils.safestring import mark_safe
from django_tables2 import RequestConfig
from django_tables2.data import TableQuerysetData
from django_tables2.utils import Accessor
from extras.models import CustomField
from .paginator import EnhancedPaginator, get_paginate_count
def stripped_value(self, **kwargs):
"""
Replaces TemplateColumn's value() method to both strip HTML tags and remove any leading/trailing whitespace.
"""
html = super(tables.TemplateColumn, self).value(**kwargs)
return strip_tags(html).strip() if isinstance(html, str) else html
# TODO: We're monkey-patching TemplateColumn here to strip leading/trailing whitespace. This will no longer
# be necessary under django-tables2 v2.3.5+. (See #5926)
tables.TemplateColumn.value = stripped_value
class BaseTable(tables.Table):
@@ -14,17 +34,23 @@ 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)
for cf in CustomField.objects.filter(content_types=obj_type):
self.base_columns[f'cf_{cf.name}'] = CustomFieldColumn(cf)
super().__init__(*args, **kwargs)
# Set default empty_text if none was provided
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
default_columns = getattr(self.Meta, 'default_columns', list())
@@ -57,6 +83,7 @@ class BaseTable(tables.Table):
# 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:
@@ -80,19 +107,20 @@ class BaseTable(tables.Table):
prefetch_fields.append('__'.join(prefetch_path))
self.data.data = self.data.data.prefetch_related(None).prefetch_related(*prefetch_fields)
@property
def configurable_columns(self):
selected_columns = [
(name, self.columns[name].verbose_name) for name in self.sequence if name not in ['pk', 'actions']
]
available_columns = [
(name, column.verbose_name) for name, column in self.columns.items() if name not in self.sequence and name not in ['pk', 'actions']
]
return selected_columns + available_columns
def _get_columns(self, visible=True):
columns = []
for name, column in self.columns.items():
if column.visible == visible and name not in ['pk', 'actions']:
columns.append((name, column.verbose_name))
return columns
@property
def visible_columns(self):
return [name for name in self.sequence if self.columns[name].visible]
def available_columns(self):
return self._get_columns(visible=False)
@property
def selected_columns(self):
return self._get_columns(visible=True)
#
@@ -212,6 +240,17 @@ class ChoiceFieldColumn(tables.Column):
return value
class ContentTypeColumn(tables.Column):
"""
Display a ContentType instance.
"""
def render(self, value):
return value.name[0].upper() + value.name[1:]
def value(self, value):
return f"{value.app_label}.{value.model}"
class ColorColumn(tables.Column):
"""
Display a color (#RRGGBB).
@@ -295,6 +334,24 @@ 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 __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
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):
"""
Display a nested hierarchy for MPTT-enabled models.
@@ -326,3 +383,18 @@ class UtilizationColumn(tables.TemplateColumn):
def value(self, value):
return f'{value}%'
#
# Pagination
#
def paginate_table(table, request):
"""
Paginate a table given a request context.
"""
paginate = {
'paginator_class': EnhancedPaginator,
'per_page': get_paginate_count(request)
}
RequestConfig(request, paginate).configure(table)