mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 19:47:20 -06:00
Closes #13269: Cache component template counts on device types
This commit is contained in:
parent
daa8f71bb6
commit
5b5444f414
@ -327,12 +327,28 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
|
||||
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
|
||||
device_count = serializers.IntegerField(read_only=True)
|
||||
|
||||
# Counter fields
|
||||
console_port_template_count = serializers.IntegerField(read_only=True)
|
||||
console_server_port_template_count = serializers.IntegerField(read_only=True)
|
||||
power_port_template_count = serializers.IntegerField(read_only=True)
|
||||
power_outlet_template_count = serializers.IntegerField(read_only=True)
|
||||
interface_template_count = serializers.IntegerField(read_only=True)
|
||||
front_port_template_count = serializers.IntegerField(read_only=True)
|
||||
rear_port_template_count = serializers.IntegerField(read_only=True)
|
||||
device_bay_template_count = serializers.IntegerField(read_only=True)
|
||||
module_bay_template_count = serializers.IntegerField(read_only=True)
|
||||
inventory_item_template_count = serializers.IntegerField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeviceType
|
||||
fields = [
|
||||
'id', 'url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
||||
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'description',
|
||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||
'id', 'url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height',
|
||||
'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image',
|
||||
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||
'console_port_template_count', 'console_server_port_template_count', 'power_port_template_count',
|
||||
'power_outlet_template_count', 'interface_template_count', 'front_port_template_count',
|
||||
'rear_port_template_count', 'device_bay_template_count', 'module_bay_template_count',
|
||||
'inventory_item_template_count',
|
||||
]
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@ class DCIMConfig(AppConfig):
|
||||
|
||||
def ready(self):
|
||||
from . import signals, search
|
||||
from .models import CableTermination, Device, VirtualChassis
|
||||
from .models import CableTermination, Device, DeviceType, VirtualChassis
|
||||
from utilities.counters import connect_counters
|
||||
|
||||
# Register denormalized fields
|
||||
@ -27,4 +27,4 @@ class DCIMConfig(AppConfig):
|
||||
})
|
||||
|
||||
# Register counters
|
||||
connect_counters(Device, VirtualChassis)
|
||||
connect_counters(Device, DeviceType, VirtualChassis)
|
||||
|
@ -32,8 +32,16 @@ def recalculate_device_counts(apps, schema_editor):
|
||||
device.inventory_item_count = device._inventory_item_count
|
||||
|
||||
Device.objects.bulk_update(devices, [
|
||||
'console_port_count', 'console_server_port_count', 'power_port_count', 'power_outlet_count', 'interface_count',
|
||||
'front_port_count', 'rear_port_count', 'device_bay_count', 'module_bay_count', 'inventory_item_count',
|
||||
'console_port_count',
|
||||
'console_server_port_count',
|
||||
'power_port_count',
|
||||
'power_outlet_count',
|
||||
'interface_count',
|
||||
'front_port_count',
|
||||
'rear_port_count',
|
||||
'device_bay_count',
|
||||
'module_bay_count',
|
||||
'inventory_item_count',
|
||||
])
|
||||
|
||||
|
||||
|
108
netbox/dcim/migrations/0177_devicetype_component_counters.py
Normal file
108
netbox/dcim/migrations/0177_devicetype_component_counters.py
Normal file
@ -0,0 +1,108 @@
|
||||
from django.db import migrations
|
||||
from django.db.models import Count
|
||||
|
||||
import utilities.fields
|
||||
|
||||
|
||||
def recalculate_devicetype_template_counts(apps, schema_editor):
|
||||
DeviceType = apps.get_model("dcim", "DeviceType")
|
||||
device_types = list(DeviceType.objects.all().annotate(
|
||||
_console_port_template_count=Count('consoleporttemplates', distinct=True),
|
||||
_console_server_port_template_count=Count('consoleserverporttemplates', distinct=True),
|
||||
_power_port_template_count=Count('powerporttemplates', distinct=True),
|
||||
_power_outlet_template_count=Count('poweroutlettemplates', distinct=True),
|
||||
_interface_template_count=Count('interfacetemplates', distinct=True),
|
||||
_front_port_template_count=Count('frontporttemplates', distinct=True),
|
||||
_rear_port_template_count=Count('rearporttemplates', distinct=True),
|
||||
_device_bay_template_count=Count('devicebaytemplates', distinct=True),
|
||||
_module_bay_template_count=Count('modulebaytemplates', distinct=True),
|
||||
_inventory_item_template_count=Count('inventoryitemtemplates', distinct=True),
|
||||
))
|
||||
|
||||
for devicetype in device_types:
|
||||
devicetype.console_port_template_count = devicetype._console_port_template_count
|
||||
devicetype.console_server_port_template_count = devicetype._console_server_port_template_count
|
||||
devicetype.power_port_template_count = devicetype._power_port_template_count
|
||||
devicetype.power_outlet_template_count = devicetype._power_outlet_template_count
|
||||
devicetype.interface_template_count = devicetype._interface_template_count
|
||||
devicetype.front_port_template_count = devicetype._front_port_template_count
|
||||
devicetype.rear_port_template_count = devicetype._rear_port_template_count
|
||||
devicetype.device_bay_template_count = devicetype._device_bay_template_count
|
||||
devicetype.module_bay_template_count = devicetype._module_bay_template_count
|
||||
devicetype.inventory_item_template_count = devicetype._inventory_item_template_count
|
||||
|
||||
DeviceType.objects.bulk_update(device_types, [
|
||||
'console_port_template_count',
|
||||
'console_server_port_template_count',
|
||||
'power_port_template_count',
|
||||
'power_outlet_template_count',
|
||||
'interface_template_count',
|
||||
'front_port_template_count',
|
||||
'rear_port_template_count',
|
||||
'device_bay_template_count',
|
||||
'module_bay_template_count',
|
||||
'inventory_item_template_count',
|
||||
])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0176_device_component_counters'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ConsolePortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_server_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ConsoleServerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.PowerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_outlet_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.PowerOutletTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='interface_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.InterfaceTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='front_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.FrontPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='rear_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.RearPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='device_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.DeviceBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='module_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ModuleBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='inventory_item_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.InventoryItemTemplate'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
recalculate_devicetype_template_counts,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
@ -17,7 +17,7 @@ def populate_virtualchassis_members(apps, schema_editor):
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0176_device_component_counters'),
|
||||
('dcim', '0177_devicetype_component_counters'),
|
||||
]
|
||||
|
||||
operations = [
|
@ -12,6 +12,7 @@ from netbox.models import ChangeLoggedModel
|
||||
from utilities.fields import ColorField, NaturalOrderingField
|
||||
from utilities.mptt import TreeManager
|
||||
from utilities.ordering import naturalize_interface
|
||||
from utilities.tracking import TrackingModelMixin
|
||||
from .device_components import (
|
||||
ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort,
|
||||
RearPort,
|
||||
@ -32,7 +33,7 @@ __all__ = (
|
||||
)
|
||||
|
||||
|
||||
class ComponentTemplateModel(ChangeLoggedModel):
|
||||
class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
|
||||
device_type = models.ForeignKey(
|
||||
to='dcim.DeviceType',
|
||||
on_delete=models.CASCADE,
|
||||
|
@ -129,6 +129,48 @@ class DeviceType(PrimaryModel, WeightMixin):
|
||||
blank=True
|
||||
)
|
||||
|
||||
# Counter fields
|
||||
console_port_template_count = CounterCacheField(
|
||||
to_model='dcim.ConsolePortTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
console_server_port_template_count = CounterCacheField(
|
||||
to_model='dcim.ConsoleServerPortTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
power_port_template_count = CounterCacheField(
|
||||
to_model='dcim.PowerPortTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
power_outlet_template_count = CounterCacheField(
|
||||
to_model='dcim.PowerOutletTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
interface_template_count = CounterCacheField(
|
||||
to_model='dcim.InterfaceTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
front_port_template_count = CounterCacheField(
|
||||
to_model='dcim.FrontPortTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
rear_port_template_count = CounterCacheField(
|
||||
to_model='dcim.RearPortTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
device_bay_template_count = CounterCacheField(
|
||||
to_model='dcim.DeviceBayTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
module_bay_template_count = CounterCacheField(
|
||||
to_model='dcim.ModuleBayTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
inventory_item_template_count = CounterCacheField(
|
||||
to_model='dcim.InventoryItemTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
|
||||
images = GenericRelation(
|
||||
to='extras.ImageAttachment'
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import django_tables2 as tables
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from dcim import models
|
||||
from netbox.tables import NetBoxTable, columns
|
||||
@ -83,11 +84,6 @@ class DeviceTypeTable(NetBoxTable):
|
||||
is_full_depth = columns.BooleanColumn(
|
||||
verbose_name='Full Depth'
|
||||
)
|
||||
instance_count = columns.LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'device_type_id': 'pk'},
|
||||
verbose_name='Instances'
|
||||
)
|
||||
comments = columns.MarkdownColumn()
|
||||
tags = columns.TagColumn(
|
||||
url_name='dcim:devicetype_list'
|
||||
@ -99,12 +95,48 @@ class DeviceTypeTable(NetBoxTable):
|
||||
template_code=WEIGHT,
|
||||
order_by=('_abs_weight', 'weight_unit')
|
||||
)
|
||||
instance_count = columns.LinkedCountColumn(
|
||||
viewname='dcim:device_list',
|
||||
url_params={'device_type_id': 'pk'},
|
||||
verbose_name='Instances'
|
||||
)
|
||||
console_port_template_count = tables.Column(
|
||||
verbose_name=_('Console ports')
|
||||
)
|
||||
console_server_port_template_count = tables.Column(
|
||||
verbose_name=_('Console server ports')
|
||||
)
|
||||
power_port_template_count = tables.Column(
|
||||
verbose_name=_('Power ports')
|
||||
)
|
||||
power_outlet_template_count = tables.Column(
|
||||
verbose_name=_('Power outlets')
|
||||
)
|
||||
interface_template_count = tables.Column(
|
||||
verbose_name=_('Interfaces')
|
||||
)
|
||||
front_port_template_count = tables.Column(
|
||||
verbose_name=_('Front ports')
|
||||
)
|
||||
rear_port_template_count = tables.Column(
|
||||
verbose_name=_('Rear ports')
|
||||
)
|
||||
device_bay_template_count = tables.Column(
|
||||
verbose_name=_('Device bays')
|
||||
)
|
||||
module_bay_template_count = tables.Column(
|
||||
verbose_name=_('Module bays')
|
||||
)
|
||||
inventory_item_template_count = tables.Column(
|
||||
verbose_name=_('Inventory items')
|
||||
)
|
||||
|
||||
class Meta(NetBoxTable.Meta):
|
||||
model = models.DeviceType
|
||||
fields = (
|
||||
'pk', 'id', 'model', 'manufacturer', 'default_platform', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||
'airflow', 'weight', 'description', 'comments', 'instance_count', 'tags', 'created', 'last_updated',
|
||||
'pk', 'id', 'model', 'manufacturer', 'default_platform', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
||||
'subdevice_role', 'airflow', 'weight', 'description', 'comments', 'instance_count', 'tags', 'created',
|
||||
'last_updated',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'instance_count',
|
||||
|
@ -951,7 +951,7 @@ class DeviceTypeConsolePortsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_consoleports'
|
||||
tab = ViewTab(
|
||||
label=_('Console Ports'),
|
||||
badge=lambda obj: obj.consoleporttemplates.count(),
|
||||
badge=lambda obj: obj.console_port_template_count,
|
||||
permission='dcim.view_consoleporttemplate',
|
||||
weight=550,
|
||||
hide_if_empty=True
|
||||
@ -966,7 +966,7 @@ class DeviceTypeConsoleServerPortsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_consoleserverports'
|
||||
tab = ViewTab(
|
||||
label=_('Console Server Ports'),
|
||||
badge=lambda obj: obj.consoleserverporttemplates.count(),
|
||||
badge=lambda obj: obj.console_server_port_template_count,
|
||||
permission='dcim.view_consoleserverporttemplate',
|
||||
weight=560,
|
||||
hide_if_empty=True
|
||||
@ -981,7 +981,7 @@ class DeviceTypePowerPortsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_powerports'
|
||||
tab = ViewTab(
|
||||
label=_('Power Ports'),
|
||||
badge=lambda obj: obj.powerporttemplates.count(),
|
||||
badge=lambda obj: obj.power_port_template_count,
|
||||
permission='dcim.view_powerporttemplate',
|
||||
weight=570,
|
||||
hide_if_empty=True
|
||||
@ -996,7 +996,7 @@ class DeviceTypePowerOutletsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_poweroutlets'
|
||||
tab = ViewTab(
|
||||
label=_('Power Outlets'),
|
||||
badge=lambda obj: obj.poweroutlettemplates.count(),
|
||||
badge=lambda obj: obj.power_outlet_template_count,
|
||||
permission='dcim.view_poweroutlettemplate',
|
||||
weight=580,
|
||||
hide_if_empty=True
|
||||
@ -1011,7 +1011,7 @@ class DeviceTypeInterfacesView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_interfaces'
|
||||
tab = ViewTab(
|
||||
label=_('Interfaces'),
|
||||
badge=lambda obj: obj.interfacetemplates.count(),
|
||||
badge=lambda obj: obj.interface_template_count,
|
||||
permission='dcim.view_interfacetemplate',
|
||||
weight=520,
|
||||
hide_if_empty=True
|
||||
@ -1026,7 +1026,7 @@ class DeviceTypeFrontPortsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_frontports'
|
||||
tab = ViewTab(
|
||||
label=_('Front Ports'),
|
||||
badge=lambda obj: obj.frontporttemplates.count(),
|
||||
badge=lambda obj: obj.front_port_template_count,
|
||||
permission='dcim.view_frontporttemplate',
|
||||
weight=530,
|
||||
hide_if_empty=True
|
||||
@ -1041,7 +1041,7 @@ class DeviceTypeRearPortsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_rearports'
|
||||
tab = ViewTab(
|
||||
label=_('Rear Ports'),
|
||||
badge=lambda obj: obj.rearporttemplates.count(),
|
||||
badge=lambda obj: obj.rear_port_template_count,
|
||||
permission='dcim.view_rearporttemplate',
|
||||
weight=540,
|
||||
hide_if_empty=True
|
||||
@ -1056,7 +1056,7 @@ class DeviceTypeModuleBaysView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_modulebays'
|
||||
tab = ViewTab(
|
||||
label=_('Module Bays'),
|
||||
badge=lambda obj: obj.modulebaytemplates.count(),
|
||||
badge=lambda obj: obj.module_bay_template_count,
|
||||
permission='dcim.view_modulebaytemplate',
|
||||
weight=510,
|
||||
hide_if_empty=True
|
||||
@ -1071,7 +1071,7 @@ class DeviceTypeDeviceBaysView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_devicebays'
|
||||
tab = ViewTab(
|
||||
label=_('Device Bays'),
|
||||
badge=lambda obj: obj.devicebaytemplates.count(),
|
||||
badge=lambda obj: obj.device_bay_template_count,
|
||||
permission='dcim.view_devicebaytemplate',
|
||||
weight=500,
|
||||
hide_if_empty=True
|
||||
@ -1086,7 +1086,7 @@ class DeviceTypeInventoryItemsView(DeviceTypeComponentsView):
|
||||
viewname = 'dcim:devicetype_inventoryitems'
|
||||
tab = ViewTab(
|
||||
label=_('Inventory Items'),
|
||||
badge=lambda obj: obj.inventoryitemtemplates.count(),
|
||||
badge=lambda obj: obj.inventory_item_template_count,
|
||||
permission='dcim.view_invenotryitemtemplate',
|
||||
weight=590,
|
||||
hide_if_empty=True
|
||||
|
Loading…
Reference in New Issue
Block a user