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

Closes #10197: Add a cached counter field for virtual chassis members

This commit is contained in:
Jeremy Stretch
2023-07-25 15:28:19 -04:00
parent 9b6e32896d
commit daa8f71bb6
7 changed files with 60 additions and 10 deletions

View File

@ -1156,13 +1156,15 @@ class CablePathSerializer(serializers.ModelSerializer):
class VirtualChassisSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
# Counter fields
member_count = serializers.IntegerField(read_only=True)
class Meta:
model = VirtualChassis
fields = [
'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
'member_count', 'created', 'last_updated',
'created', 'last_updated', 'member_count',
]

View File

@ -579,9 +579,7 @@ class CableTerminationViewSet(NetBoxModelViewSet):
#
class VirtualChassisViewSet(NetBoxModelViewSet):
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
member_count=count_related(Device, 'virtual_chassis')
)
queryset = VirtualChassis.objects.prefetch_related('tags')
serializer_class = serializers.VirtualChassisSerializer
filterset_class = filtersets.VirtualChassisFilterSet
brief_prefetch_fields = ['master']

View File

@ -9,7 +9,7 @@ class DCIMConfig(AppConfig):
def ready(self):
from . import signals, search
from .models import CableTermination, Device
from .models import CableTermination, Device, VirtualChassis
from utilities.counters import connect_counters
# Register denormalized fields
@ -27,4 +27,4 @@ class DCIMConfig(AppConfig):
})
# Register counters
connect_counters(Device)
connect_counters(Device, VirtualChassis)

View File

@ -0,0 +1,35 @@
from django.db import migrations
from django.db.models import Count
import utilities.fields
def populate_virtualchassis_members(apps, schema_editor):
VirtualChassis = apps.get_model('dcim', 'VirtualChassis')
vcs = list(VirtualChassis.objects.annotate(_member_count=Count('members', distinct=True)))
for vc in vcs:
vc.member_count = vc._member_count
VirtualChassis.objects.bulk_update(vcs, ['member_count'])
class Migration(migrations.Migration):
dependencies = [
('dcim', '0176_device_component_counters'),
]
operations = [
migrations.AddField(
model_name='virtualchassis',
name='member_count',
field=utilities.fields.CounterCacheField(
default=0, to_field='virtual_chassis', to_model='dcim.Device'
),
),
migrations.RunPython(
code=populate_virtualchassis_members,
reverse_code=migrations.RunPython.noop
),
]

View File

@ -22,6 +22,7 @@ from netbox.config import ConfigItem
from netbox.models import OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField
from utilities.tracking import TrackingModelMixin
from .device_components import *
from .mixins import WeightMixin
@ -469,7 +470,7 @@ def update_interface_bridges(device, interface_templates, module=None):
interface.save()
class Device(PrimaryModel, ConfigContextModel):
class Device(PrimaryModel, ConfigContextModel, TrackingModelMixin):
"""
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
DeviceRole, and (optionally) a Platform. Device names are not required, however if one is set it must be unique.
@ -1206,6 +1207,12 @@ class VirtualChassis(PrimaryModel):
blank=True
)
# Counter fields
member_count = CounterCacheField(
to_model='dcim.Device',
to_field='virtual_chassis'
)
class Meta:
ordering = ['name']
verbose_name_plural = 'virtual chassis'

View File

@ -3227,9 +3227,7 @@ class InterfaceConnectionsListView(generic.ObjectListView):
#
class VirtualChassisListView(generic.ObjectListView):
queryset = VirtualChassis.objects.annotate(
member_count=count_related(Device, 'virtual_chassis')
)
queryset = VirtualChassis.objects.all()
table = tables.VirtualChassisTable
filterset = filtersets.VirtualChassisFilterSet
filterset_form = forms.VirtualChassisFilterForm

View File

@ -31,6 +31,16 @@
<th scope="row">Description</th>
<td>{{ object.description|placeholder }}</td>
</tr>
<tr>
<th scope="row">Members</th>
<td>
{% if object.member_count %}
<a href="{% url 'dcim:device_list' %}?virtual_chassis_id={{ object.pk }}">{{ object.member_count }}</a>
{% else %}
{{ object.member_count }}
{% endif %}
</td>
</tr>
</table>
</div>
</div>