mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Introduce LinkedCountColumn to standardize approach to counting related items in tables
This commit is contained in:
@ -3,8 +3,8 @@ from django_tables2.utils import Accessor
|
||||
|
||||
from tenancy.tables import COL_TENANT
|
||||
from utilities.tables import (
|
||||
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, TagColumn,
|
||||
ToggleColumn,
|
||||
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
|
||||
TagColumn, ToggleColumn,
|
||||
)
|
||||
from .models import (
|
||||
Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
|
||||
@ -49,14 +49,6 @@ RACKGROUP_ELEVATIONS = """
|
||||
</a>
|
||||
"""
|
||||
|
||||
RACK_DEVICE_COUNT = """
|
||||
<a href="{% url 'dcim:device_list' %}?rack_id={{ record.pk }}">{{ value }}</a>
|
||||
"""
|
||||
|
||||
DEVICE_COUNT = """
|
||||
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
RACKRESERVATION_ACTIONS = """
|
||||
<a href="{% url 'dcim:rackreservation_changelog' pk=record.pk %}" class="btn btn-default btn-xs" title="Change log">
|
||||
<i class="fa fa-history"></i>
|
||||
@ -75,14 +67,6 @@ MANUFACTURER_ACTIONS = """
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
DEVICEROLE_DEVICE_COUNT = """
|
||||
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
DEVICEROLE_VM_COUNT = """
|
||||
<a href="{% url 'virtualization:virtualmachine_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
DEVICEROLE_ACTIONS = """
|
||||
<a href="{% url 'dcim:devicerole_changelog' slug=record.slug %}" class="btn btn-default btn-xs" title="Change log">
|
||||
<i class="fa fa-history"></i>
|
||||
@ -92,24 +76,12 @@ DEVICEROLE_ACTIONS = """
|
||||
{% endif %}
|
||||
"""
|
||||
|
||||
PLATFORM_DEVICE_COUNT = """
|
||||
<a href="{% url 'dcim:device_list' %}?platform={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
PLATFORM_VM_COUNT = """
|
||||
<a href="{% url 'virtualization:virtualmachine_list' %}?platform={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
DEVICE_PRIMARY_IP = """
|
||||
{{ record.primary_ip6.address.ip|default:"" }}
|
||||
{% if record.primary_ip6 and record.primary_ip4 %}<br />{% endif %}
|
||||
{{ record.primary_ip4.address.ip|default:"" }}
|
||||
"""
|
||||
|
||||
DEVICETYPE_INSTANCES_TEMPLATE = """
|
||||
<a href="{% url 'dcim:device_list' %}?manufacturer_id={{ record.manufacturer_id }}&device_type_id={{ record.pk }}">{{ record.instance_count }}</a>
|
||||
"""
|
||||
|
||||
UTILIZATION_GRAPH = """
|
||||
{% load helpers %}
|
||||
{% utilization_graph value %}
|
||||
@ -129,10 +101,6 @@ CABLE_LENGTH = """
|
||||
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% else %}—{% endif %}
|
||||
"""
|
||||
|
||||
POWERPANEL_POWERFEED_COUNT = """
|
||||
<a href="{% url 'dcim:powerfeed_list' %}?power_panel_id={{ record.pk }}">{{ value }}</a>
|
||||
"""
|
||||
|
||||
INTERFACE_IPADDRESSES = """
|
||||
{% for ip in record.ip_addresses.unrestricted %}
|
||||
<a href="{{ ip.get_absolute_url }}">{{ ip }}</a><br />
|
||||
@ -280,8 +248,9 @@ class RackTable(BaseTable):
|
||||
|
||||
|
||||
class RackDetailTable(RackTable):
|
||||
device_count = tables.TemplateColumn(
|
||||
template_code=RACK_DEVICE_COUNT,
|
||||
device_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'rack_id': 'pk'},
|
||||
verbose_name='Devices'
|
||||
)
|
||||
get_utilization = tables.TemplateColumn(
|
||||
@ -388,8 +357,9 @@ class DeviceTypeTable(BaseTable):
|
||||
is_full_depth = BooleanColumn(
|
||||
verbose_name='Full Depth'
|
||||
)
|
||||
instance_count = tables.TemplateColumn(
|
||||
template_code=DEVICETYPE_INSTANCES_TEMPLATE,
|
||||
instance_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'device_type_id': 'pk'},
|
||||
verbose_name='Instances'
|
||||
)
|
||||
tags = TagColumn(
|
||||
@ -526,12 +496,14 @@ class DeviceBayTemplateTable(ComponentTemplateTable):
|
||||
|
||||
class DeviceRoleTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
device_count = tables.TemplateColumn(
|
||||
template_code=DEVICEROLE_DEVICE_COUNT,
|
||||
device_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'role': 'slug'},
|
||||
verbose_name='Devices'
|
||||
)
|
||||
vm_count = tables.TemplateColumn(
|
||||
template_code=DEVICEROLE_VM_COUNT,
|
||||
vm_count = LinkedCountColumn(
|
||||
viewname='virtualization:virtualmachine_list',
|
||||
url_params={'role': 'slug'},
|
||||
verbose_name='VMs'
|
||||
)
|
||||
color = tables.TemplateColumn(
|
||||
@ -553,12 +525,14 @@ class DeviceRoleTable(BaseTable):
|
||||
|
||||
class PlatformTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
device_count = tables.TemplateColumn(
|
||||
template_code=PLATFORM_DEVICE_COUNT,
|
||||
device_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'platform': 'slug'},
|
||||
verbose_name='Devices'
|
||||
)
|
||||
vm_count = tables.TemplateColumn(
|
||||
template_code=PLATFORM_VM_COUNT,
|
||||
vm_count = LinkedCountColumn(
|
||||
viewname='virtualization:virtualmachine_list',
|
||||
url_params={'platform': 'slug'},
|
||||
verbose_name='VMs'
|
||||
)
|
||||
actions = ButtonsColumn(Platform, pk_field='slug')
|
||||
@ -994,7 +968,9 @@ class VirtualChassisTable(BaseTable):
|
||||
master = tables.Column(
|
||||
linkify=True
|
||||
)
|
||||
member_count = tables.Column(
|
||||
member_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'virtual_chassis_id': 'pk'},
|
||||
verbose_name='Members'
|
||||
)
|
||||
tags = TagColumn(
|
||||
@ -1018,8 +994,9 @@ class PowerPanelTable(BaseTable):
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site__slug')]
|
||||
)
|
||||
powerfeed_count = tables.TemplateColumn(
|
||||
template_code=POWERPANEL_POWERFEED_COUNT,
|
||||
powerfeed_count = LinkedCountColumn(
|
||||
viewname='dcim:powerfeed_list',
|
||||
url_params={'power_panel_id': 'pk'},
|
||||
verbose_name='Feeds'
|
||||
)
|
||||
tags = TagColumn(
|
||||
|
@ -4,7 +4,9 @@ from django_tables2.utils import Accessor
|
||||
|
||||
from dcim.models import Interface
|
||||
from tenancy.tables import COL_TENANT
|
||||
from utilities.tables import BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, TagColumn, ToggleColumn
|
||||
from utilities.tables import (
|
||||
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, LinkedCountColumn, TagColumn, ToggleColumn,
|
||||
)
|
||||
from virtualization.models import VMInterface
|
||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
|
||||
|
||||
@ -34,14 +36,6 @@ UTILIZATION_GRAPH = """
|
||||
{% if record.pk %}{% utilization_graph record.get_utilization %}{% else %}—{% endif %}
|
||||
"""
|
||||
|
||||
ROLE_PREFIX_COUNT = """
|
||||
<a href="{% url 'ipam:prefix_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
ROLE_VLAN_COUNT = """
|
||||
<a href="{% url 'ipam:vlan_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
PREFIX_LINK = """
|
||||
{% if record.children %}
|
||||
<span class="text-nowrap" style="padding-left: {{ record.parents }}0px "><i class="fa fa-caret-right"></i></a>
|
||||
@ -209,7 +203,9 @@ class RIRTable(BaseTable):
|
||||
is_private = BooleanColumn(
|
||||
verbose_name='Private'
|
||||
)
|
||||
aggregate_count = tables.Column(
|
||||
aggregate_count = LinkedCountColumn(
|
||||
viewname='ipam:aggregate_list',
|
||||
url_params={'rir': 'slug'},
|
||||
verbose_name='Aggregates'
|
||||
)
|
||||
actions = ButtonsColumn(RIR, pk_field='slug')
|
||||
@ -304,12 +300,14 @@ class AggregateDetailTable(AggregateTable):
|
||||
|
||||
class RoleTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
prefix_count = tables.TemplateColumn(
|
||||
template_code=ROLE_PREFIX_COUNT,
|
||||
prefix_count = LinkedCountColumn(
|
||||
viewname='ipam:prefix_list',
|
||||
url_params={'role': 'slug'},
|
||||
verbose_name='Prefixes'
|
||||
)
|
||||
vlan_count = tables.TemplateColumn(
|
||||
template_code=ROLE_VLAN_COUNT,
|
||||
vlan_count = LinkedCountColumn(
|
||||
viewname='ipam:vlan_list',
|
||||
url_params={'role': 'slug'},
|
||||
verbose_name='VLANs'
|
||||
)
|
||||
actions = ButtonsColumn(Role, pk_field='slug')
|
||||
@ -508,7 +506,9 @@ class VLANGroupTable(BaseTable):
|
||||
viewname='dcim:site',
|
||||
args=[Accessor('site__slug')]
|
||||
)
|
||||
vlan_count = tables.Column(
|
||||
vlan_count = LinkedCountColumn(
|
||||
viewname='ipam:vlan_list',
|
||||
url_params={'group': 'slug'},
|
||||
verbose_name='VLANs'
|
||||
)
|
||||
actions = ButtonsColumn(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import django_tables2 as tables
|
||||
|
||||
from utilities.tables import BaseTable, ButtonsColumn, TagColumn, ToggleColumn
|
||||
from utilities.tables import BaseTable, ButtonsColumn, LinkedCountColumn, TagColumn, ToggleColumn
|
||||
from .models import SecretRole, Secret
|
||||
|
||||
|
||||
@ -11,7 +11,9 @@ from .models import SecretRole, Secret
|
||||
class SecretRoleTable(BaseTable):
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
secret_count = tables.Column(
|
||||
secret_count = LinkedCountColumn(
|
||||
viewname='secrets:secret_list',
|
||||
url_params={'role': 'slug'},
|
||||
verbose_name='Secrets'
|
||||
)
|
||||
actions = ButtonsColumn(SecretRole, pk_field='slug')
|
||||
|
@ -1,6 +1,6 @@
|
||||
import django_tables2 as tables
|
||||
|
||||
from utilities.tables import BaseTable, ButtonsColumn, TagColumn, ToggleColumn
|
||||
from utilities.tables import BaseTable, ButtonsColumn, LinkedCountColumn, TagColumn, ToggleColumn
|
||||
from .models import Tenant, TenantGroup
|
||||
|
||||
MPTT_LINK = """
|
||||
@ -32,7 +32,9 @@ class TenantGroupTable(BaseTable):
|
||||
template_code=MPTT_LINK,
|
||||
orderable=False
|
||||
)
|
||||
tenant_count = tables.Column(
|
||||
tenant_count = LinkedCountColumn(
|
||||
viewname='tenancy:tenant_list',
|
||||
url_params={'group': 'slug'},
|
||||
verbose_name='Tenants'
|
||||
)
|
||||
actions = ButtonsColumn(TenantGroup, pk_field='slug')
|
||||
|
@ -1,6 +1,7 @@
|
||||
import django_tables2 as tables
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models.fields.related import RelatedField
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import mark_safe
|
||||
from django_tables2.data import TableQuerysetData
|
||||
|
||||
@ -213,6 +214,29 @@ class ColoredLabelColumn(tables.TemplateColumn):
|
||||
super().__init__(template_code=self.template_code, *args, **kwargs)
|
||||
|
||||
|
||||
class LinkedCountColumn(tables.Column):
|
||||
"""
|
||||
Render a count of related objects linked to a filtered URL.
|
||||
|
||||
:param viewname: The view name to use for URL resolution
|
||||
:param view_kwargs: Additional kwargs to pass for URL resolution (optional)
|
||||
:param url_params: A dict of query parameters to append to the URL (e.g. ?foo=bar) (optional)
|
||||
"""
|
||||
def __init__(self, viewname, *args, view_kwargs=None, url_params=None, default=0, **kwargs):
|
||||
self.viewname = viewname
|
||||
self.view_kwargs = view_kwargs or {}
|
||||
self.url_params = url_params
|
||||
super().__init__(*args, default=default, **kwargs)
|
||||
|
||||
def render(self, record, value):
|
||||
if value:
|
||||
url = reverse(self.viewname, kwargs=self.view_kwargs)
|
||||
if self.url_params:
|
||||
url += '?' + '&'.join([f'{k}={getattr(record, v)}' for k, v in self.url_params.items()])
|
||||
return mark_safe(f'<a href="{url}">{value}</a>')
|
||||
return value
|
||||
|
||||
|
||||
class TagColumn(tables.TemplateColumn):
|
||||
"""
|
||||
Display a list of tags assigned to the object.
|
||||
|
@ -2,7 +2,9 @@ import django_tables2 as tables
|
||||
|
||||
from dcim.tables import BaseInterfaceTable
|
||||
from tenancy.tables import COL_TENANT
|
||||
from utilities.tables import BaseTable, ButtonsColumn, ChoiceFieldColumn, ColoredLabelColumn, TagColumn, ToggleColumn
|
||||
from utilities.tables import (
|
||||
BaseTable, ButtonsColumn, ChoiceFieldColumn, ColoredLabelColumn, LinkedCountColumn, TagColumn, ToggleColumn,
|
||||
)
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
||||
|
||||
VIRTUALMACHINE_PRIMARY_IP = """
|
||||
@ -11,14 +13,6 @@ VIRTUALMACHINE_PRIMARY_IP = """
|
||||
{{ record.primary_ip4.address.ip|default:"" }}
|
||||
"""
|
||||
|
||||
DEVICE_COUNT = """
|
||||
<a href="{% url 'dcim:device_list' %}?cluster_id={{ record.pk }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
VM_COUNT = """
|
||||
<a href="{% url 'virtualization:virtualmachine_list' %}?cluster_id={{ record.pk }}">{{ value|default:0 }}</a>
|
||||
"""
|
||||
|
||||
|
||||
#
|
||||
# Cluster types
|
||||
@ -69,12 +63,14 @@ class ClusterTable(BaseTable):
|
||||
site = tables.Column(
|
||||
linkify=True
|
||||
)
|
||||
device_count = tables.TemplateColumn(
|
||||
template_code=DEVICE_COUNT,
|
||||
device_count = LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'cluster_id': 'pk'},
|
||||
verbose_name='Devices'
|
||||
)
|
||||
vm_count = tables.TemplateColumn(
|
||||
template_code=VM_COUNT,
|
||||
vm_count = LinkedCountColumn(
|
||||
viewname='virtualization:virtualmachine_list',
|
||||
url_params={'cluster_id': 'pk'},
|
||||
verbose_name='VMs'
|
||||
)
|
||||
tags = TagColumn(
|
||||
|
Reference in New Issue
Block a user