1
0
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:
Jeremy Stretch
2020-07-10 15:38:54 -04:00
parent 683ba5eed3
commit a260019a7f
6 changed files with 47 additions and 45 deletions

View File

@ -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(

View File

@ -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

View File

@ -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')]

View File

@ -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

View File

@ -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(

View File

@ -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