mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
#4843: Use subqueries when counting multiple types of related objects
This commit is contained in:
@ -103,20 +103,12 @@ DEVICEROLE_ACTIONS = """
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEVICEROLE_DEVICE_COUNT = """
|
DEVICE_COUNT = """
|
||||||
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value }}</a>
|
<a href="{% url 'dcim:device_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEVICEROLE_VM_COUNT = """
|
VM_COUNT = """
|
||||||
<a href="{% url 'virtualization:virtualmachine_list' %}?role={{ record.slug }}">{{ value }}</a>
|
<a href="{% url 'virtualization:virtualmachine_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
|
||||||
|
|
||||||
PLATFORM_DEVICE_COUNT = """
|
|
||||||
<a href="{% url 'dcim:device_list' %}?platform={{ record.slug }}">{{ value }}</a>
|
|
||||||
"""
|
|
||||||
|
|
||||||
PLATFORM_VM_COUNT = """
|
|
||||||
<a href="{% url 'virtualization:virtualmachine_list' %}?platform={{ record.slug }}">{{ value }}</a>
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PLATFORM_ACTIONS = """
|
PLATFORM_ACTIONS = """
|
||||||
@ -278,6 +270,7 @@ class RackGroupTable(BaseTable):
|
|||||||
|
|
||||||
class RackRoleTable(BaseTable):
|
class RackRoleTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
|
name = tables.Column(linkify=True)
|
||||||
rack_count = tables.Column(verbose_name='Racks')
|
rack_count = tables.Column(verbose_name='Racks')
|
||||||
color = tables.TemplateColumn(COLOR_LABEL)
|
color = tables.TemplateColumn(COLOR_LABEL)
|
||||||
actions = tables.TemplateColumn(
|
actions = tables.TemplateColumn(
|
||||||
@ -704,21 +697,18 @@ class DeviceBayTemplateTable(BaseTable):
|
|||||||
class DeviceRoleTable(BaseTable):
|
class DeviceRoleTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
device_count = tables.TemplateColumn(
|
device_count = tables.TemplateColumn(
|
||||||
template_code=DEVICEROLE_DEVICE_COUNT,
|
template_code=DEVICE_COUNT,
|
||||||
accessor=Accessor('devices.count'),
|
|
||||||
orderable=False,
|
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
vm_count = tables.TemplateColumn(
|
vm_count = tables.TemplateColumn(
|
||||||
template_code=DEVICEROLE_VM_COUNT,
|
template_code=VM_COUNT,
|
||||||
accessor=Accessor('virtual_machines.count'),
|
|
||||||
orderable=False,
|
|
||||||
verbose_name='VMs'
|
verbose_name='VMs'
|
||||||
)
|
)
|
||||||
color = tables.TemplateColumn(
|
color = tables.TemplateColumn(
|
||||||
template_code=COLOR_LABEL,
|
template_code=COLOR_LABEL,
|
||||||
verbose_name='Label'
|
verbose_name='Label'
|
||||||
)
|
)
|
||||||
|
vm_role = BooleanColumn()
|
||||||
actions = tables.TemplateColumn(
|
actions = tables.TemplateColumn(
|
||||||
template_code=DEVICEROLE_ACTIONS,
|
template_code=DEVICEROLE_ACTIONS,
|
||||||
attrs={'td': {'class': 'text-right noprint'}},
|
attrs={'td': {'class': 'text-right noprint'}},
|
||||||
@ -738,15 +728,11 @@ class DeviceRoleTable(BaseTable):
|
|||||||
class PlatformTable(BaseTable):
|
class PlatformTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
device_count = tables.TemplateColumn(
|
device_count = tables.TemplateColumn(
|
||||||
template_code=PLATFORM_DEVICE_COUNT,
|
template_code=DEVICE_COUNT,
|
||||||
accessor=Accessor('devices.count'),
|
|
||||||
orderable=False,
|
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
vm_count = tables.TemplateColumn(
|
vm_count = tables.TemplateColumn(
|
||||||
template_code=PLATFORM_VM_COUNT,
|
template_code=VM_COUNT,
|
||||||
accessor=Accessor('virtual_machines.count'),
|
|
||||||
orderable=False,
|
|
||||||
verbose_name='VMs'
|
verbose_name='VMs'
|
||||||
)
|
)
|
||||||
actions = tables.TemplateColumn(
|
actions = tables.TemplateColumn(
|
||||||
|
@ -23,7 +23,7 @@ from ipam.models import Prefix, VLAN
|
|||||||
from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
|
from ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.paginator import EnhancedPaginator
|
from utilities.paginator import EnhancedPaginator
|
||||||
from utilities.utils import csv_format
|
from utilities.utils import csv_format, get_subquery
|
||||||
from utilities.views import (
|
from utilities.views import (
|
||||||
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, GetReturnURLMixin,
|
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, GetReturnURLMixin,
|
||||||
ObjectImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
ObjectImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||||
@ -557,9 +557,9 @@ class RackReservationBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
class ManufacturerListView(PermissionRequiredMixin, ObjectListView):
|
class ManufacturerListView(PermissionRequiredMixin, ObjectListView):
|
||||||
permission_required = 'dcim.view_manufacturer'
|
permission_required = 'dcim.view_manufacturer'
|
||||||
queryset = Manufacturer.objects.annotate(
|
queryset = Manufacturer.objects.annotate(
|
||||||
devicetype_count=Count('device_types', distinct=True),
|
devicetype_count=get_subquery(DeviceType, 'manufacturer'),
|
||||||
inventoryitem_count=Count('inventory_items', distinct=True),
|
inventoryitem_count=get_subquery(InventoryItem, 'manufacturer'),
|
||||||
platform_count=Count('platforms', distinct=True),
|
platform_count=get_subquery(Platform, 'manufacturer')
|
||||||
)
|
)
|
||||||
table = tables.ManufacturerTable
|
table = tables.ManufacturerTable
|
||||||
|
|
||||||
@ -1020,7 +1020,10 @@ class DeviceBayTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
|
|
||||||
class DeviceRoleListView(PermissionRequiredMixin, ObjectListView):
|
class DeviceRoleListView(PermissionRequiredMixin, ObjectListView):
|
||||||
permission_required = 'dcim.view_devicerole'
|
permission_required = 'dcim.view_devicerole'
|
||||||
queryset = DeviceRole.objects.all()
|
queryset = DeviceRole.objects.annotate(
|
||||||
|
device_count=get_subquery(Device, 'device_role'),
|
||||||
|
vm_count=get_subquery(VirtualMachine, 'role')
|
||||||
|
)
|
||||||
table = tables.DeviceRoleTable
|
table = tables.DeviceRoleTable
|
||||||
|
|
||||||
|
|
||||||
@ -1055,7 +1058,10 @@ class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
|
|
||||||
class PlatformListView(PermissionRequiredMixin, ObjectListView):
|
class PlatformListView(PermissionRequiredMixin, ObjectListView):
|
||||||
permission_required = 'dcim.view_platform'
|
permission_required = 'dcim.view_platform'
|
||||||
queryset = Platform.objects.all()
|
queryset = Platform.objects.annotate(
|
||||||
|
device_count=get_subquery(Device, 'device_role'),
|
||||||
|
vm_count=get_subquery(VirtualMachine, 'role')
|
||||||
|
)
|
||||||
table = tables.PlatformTable
|
table = tables.PlatformTable
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,11 +40,11 @@ UTILIZATION_GRAPH = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
ROLE_PREFIX_COUNT = """
|
ROLE_PREFIX_COUNT = """
|
||||||
<a href="{% url 'ipam:prefix_list' %}?role={{ record.slug }}">{{ value }}</a>
|
<a href="{% url 'ipam:prefix_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ROLE_VLAN_COUNT = """
|
ROLE_VLAN_COUNT = """
|
||||||
<a href="{% url 'ipam:vlan_list' %}?role={{ record.slug }}">{{ value }}</a>
|
<a href="{% url 'ipam:vlan_list' %}?role={{ record.slug }}">{{ value|default:0 }}</a>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ROLE_ACTIONS = """
|
ROLE_ACTIONS = """
|
||||||
@ -319,15 +319,11 @@ class AggregateDetailTable(AggregateTable):
|
|||||||
class RoleTable(BaseTable):
|
class RoleTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
prefix_count = tables.TemplateColumn(
|
prefix_count = tables.TemplateColumn(
|
||||||
accessor=Accessor('prefixes.count'),
|
|
||||||
template_code=ROLE_PREFIX_COUNT,
|
template_code=ROLE_PREFIX_COUNT,
|
||||||
orderable=False,
|
|
||||||
verbose_name='Prefixes'
|
verbose_name='Prefixes'
|
||||||
)
|
)
|
||||||
vlan_count = tables.TemplateColumn(
|
vlan_count = tables.TemplateColumn(
|
||||||
accessor=Accessor('vlans.count'),
|
|
||||||
template_code=ROLE_VLAN_COUNT,
|
template_code=ROLE_VLAN_COUNT,
|
||||||
orderable=False,
|
|
||||||
verbose_name='VLANs'
|
verbose_name='VLANs'
|
||||||
)
|
)
|
||||||
actions = tables.TemplateColumn(
|
actions = tables.TemplateColumn(
|
||||||
@ -524,7 +520,7 @@ class InterfaceIPAddressTable(BaseTable):
|
|||||||
|
|
||||||
class VLANGroupTable(BaseTable):
|
class VLANGroupTable(BaseTable):
|
||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
name = tables.LinkColumn()
|
name = tables.Column(linkify=True)
|
||||||
site = tables.LinkColumn(
|
site = tables.LinkColumn(
|
||||||
viewname='dcim:site',
|
viewname='dcim:site',
|
||||||
args=[Accessor('site.slug')]
|
args=[Accessor('site.slug')]
|
||||||
|
@ -9,6 +9,7 @@ from django_tables2 import RequestConfig
|
|||||||
|
|
||||||
from dcim.models import Device, Interface
|
from dcim.models import Device, Interface
|
||||||
from utilities.paginator import EnhancedPaginator
|
from utilities.paginator import EnhancedPaginator
|
||||||
|
from utilities.utils import get_subquery
|
||||||
from utilities.views import (
|
from utilities.views import (
|
||||||
BulkCreateView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
BulkCreateView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||||
)
|
)
|
||||||
@ -407,7 +408,10 @@ class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
|
|
||||||
class RoleListView(PermissionRequiredMixin, ObjectListView):
|
class RoleListView(PermissionRequiredMixin, ObjectListView):
|
||||||
permission_required = 'ipam.view_role'
|
permission_required = 'ipam.view_role'
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.annotate(
|
||||||
|
prefix_count=get_subquery(Prefix, 'role'),
|
||||||
|
vlan_count=get_subquery(VLAN, 'role')
|
||||||
|
)
|
||||||
table = tables.RoleTable
|
table = tables.RoleTable
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +34,14 @@ VIRTUALMACHINE_PRIMARY_IP = """
|
|||||||
{{ record.primary_ip4.address.ip|default:"" }}
|
{{ record.primary_ip4.address.ip|default:"" }}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CLUSTER_DEVICE_COUNT = """
|
||||||
|
<a href="{% url 'dcim:device_list' %}?cluster_id={{ record.pk }}">{{ value|default:0 }}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
CLUSTER_VM_COUNT = """
|
||||||
|
<a href="{% url 'virtualization:virtualmachine_list' %}?cluster_id={{ record.pk }}">{{ value|default:0 }}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cluster types
|
# Cluster types
|
||||||
@ -94,14 +102,12 @@ class ClusterTable(BaseTable):
|
|||||||
viewname='dcim:site',
|
viewname='dcim:site',
|
||||||
args=[Accessor('site.slug')]
|
args=[Accessor('site.slug')]
|
||||||
)
|
)
|
||||||
device_count = tables.Column(
|
device_count = tables.TemplateColumn(
|
||||||
accessor=Accessor('devices.count'),
|
template_code=CLUSTER_DEVICE_COUNT,
|
||||||
orderable=False,
|
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
vm_count = tables.Column(
|
vm_count = tables.TemplateColumn(
|
||||||
accessor=Accessor('virtual_machines.count'),
|
template_code=CLUSTER_VM_COUNT,
|
||||||
orderable=False,
|
|
||||||
verbose_name='VMs'
|
verbose_name='VMs'
|
||||||
)
|
)
|
||||||
tags = TagColumn(
|
tags = TagColumn(
|
||||||
|
@ -10,6 +10,7 @@ from dcim.models import Device, Interface
|
|||||||
from dcim.tables import DeviceTable
|
from dcim.tables import DeviceTable
|
||||||
from extras.views import ObjectConfigContextView
|
from extras.views import ObjectConfigContextView
|
||||||
from ipam.models import Service
|
from ipam.models import Service
|
||||||
|
from utilities.utils import get_subquery
|
||||||
from utilities.views import (
|
from utilities.views import (
|
||||||
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ObjectDeleteView,
|
BulkComponentCreateView, BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ObjectDeleteView,
|
||||||
ObjectEditView, ObjectListView,
|
ObjectEditView, ObjectListView,
|
||||||
@ -94,7 +95,10 @@ class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
|
|
||||||
class ClusterListView(PermissionRequiredMixin, ObjectListView):
|
class ClusterListView(PermissionRequiredMixin, ObjectListView):
|
||||||
permission_required = 'virtualization.view_cluster'
|
permission_required = 'virtualization.view_cluster'
|
||||||
queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant')
|
queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant').annotate(
|
||||||
|
device_count=get_subquery(Device, 'cluster'),
|
||||||
|
vm_count=get_subquery(VirtualMachine, 'cluster')
|
||||||
|
)
|
||||||
table = tables.ClusterTable
|
table = tables.ClusterTable
|
||||||
filterset = filters.ClusterFilterSet
|
filterset = filters.ClusterFilterSet
|
||||||
filterset_form = forms.ClusterFilterForm
|
filterset_form = forms.ClusterFilterForm
|
||||||
|
Reference in New Issue
Block a user