Skip to content

Commit daa8f71

Browse files
committed
Closes #10197: Add a cached counter field for virtual chassis members
1 parent 9b6e328 commit daa8f71

File tree

7 files changed

+60
-10
lines changed

7 files changed

+60
-10
lines changed

netbox/dcim/api/serializers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1156,13 +1156,15 @@ def get_path(self, obj):
11561156
class VirtualChassisSerializer(NetBoxModelSerializer):
11571157
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
11581158
master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
1159+
1160+
# Counter fields
11591161
member_count = serializers.IntegerField(read_only=True)
11601162

11611163
class Meta:
11621164
model = VirtualChassis
11631165
fields = [
11641166
'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
1165-
'member_count', 'created', 'last_updated',
1167+
'created', 'last_updated', 'member_count',
11661168
]
11671169

11681170

netbox/dcim/api/views.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -579,9 +579,7 @@ class CableTerminationViewSet(NetBoxModelViewSet):
579579
#
580580

581581
class VirtualChassisViewSet(NetBoxModelViewSet):
582-
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
583-
member_count=count_related(Device, 'virtual_chassis')
584-
)
582+
queryset = VirtualChassis.objects.prefetch_related('tags')
585583
serializer_class = serializers.VirtualChassisSerializer
586584
filterset_class = filtersets.VirtualChassisFilterSet
587585
brief_prefetch_fields = ['master']

netbox/dcim/apps.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class DCIMConfig(AppConfig):
99

1010
def ready(self):
1111
from . import signals, search
12-
from .models import CableTermination, Device
12+
from .models import CableTermination, Device, VirtualChassis
1313
from utilities.counters import connect_counters
1414

1515
# Register denormalized fields
@@ -27,4 +27,4 @@ def ready(self):
2727
})
2828

2929
# Register counters
30-
connect_counters(Device)
30+
connect_counters(Device, VirtualChassis)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from django.db import migrations
2+
from django.db.models import Count
3+
4+
import utilities.fields
5+
6+
7+
def populate_virtualchassis_members(apps, schema_editor):
8+
VirtualChassis = apps.get_model('dcim', 'VirtualChassis')
9+
10+
vcs = list(VirtualChassis.objects.annotate(_member_count=Count('members', distinct=True)))
11+
12+
for vc in vcs:
13+
vc.member_count = vc._member_count
14+
15+
VirtualChassis.objects.bulk_update(vcs, ['member_count'])
16+
17+
18+
class Migration(migrations.Migration):
19+
dependencies = [
20+
('dcim', '0176_device_component_counters'),
21+
]
22+
23+
operations = [
24+
migrations.AddField(
25+
model_name='virtualchassis',
26+
name='member_count',
27+
field=utilities.fields.CounterCacheField(
28+
default=0, to_field='virtual_chassis', to_model='dcim.Device'
29+
),
30+
),
31+
migrations.RunPython(
32+
code=populate_virtualchassis_members,
33+
reverse_code=migrations.RunPython.noop
34+
),
35+
]

netbox/dcim/models/devices.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from netbox.models import OrganizationalModel, PrimaryModel
2323
from utilities.choices import ColorChoices
2424
from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField
25+
from utilities.tracking import TrackingModelMixin
2526
from .device_components import *
2627
from .mixins import WeightMixin
2728

@@ -469,7 +470,7 @@ def update_interface_bridges(device, interface_templates, module=None):
469470
interface.save()
470471

471472

472-
class Device(PrimaryModel, ConfigContextModel):
473+
class Device(PrimaryModel, ConfigContextModel, TrackingModelMixin):
473474
"""
474475
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
475476
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):
12061207
blank=True
12071208
)
12081209

1210+
# Counter fields
1211+
member_count = CounterCacheField(
1212+
to_model='dcim.Device',
1213+
to_field='virtual_chassis'
1214+
)
1215+
12091216
class Meta:
12101217
ordering = ['name']
12111218
verbose_name_plural = 'virtual chassis'

netbox/dcim/views.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -3227,9 +3227,7 @@ def get_extra_context(self, request):
32273227
#
32283228

32293229
class VirtualChassisListView(generic.ObjectListView):
3230-
queryset = VirtualChassis.objects.annotate(
3231-
member_count=count_related(Device, 'virtual_chassis')
3232-
)
3230+
queryset = VirtualChassis.objects.all()
32333231
table = tables.VirtualChassisTable
32343232
filterset = filtersets.VirtualChassisFilterSet
32353233
filterset_form = forms.VirtualChassisFilterForm

netbox/templates/dcim/virtualchassis.html

+10
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ <h5 class="card-header">Virtual Chassis</h5>
3131
<th scope="row">Description</th>
3232
<td>{{ object.description|placeholder }}</td>
3333
</tr>
34+
<tr>
35+
<th scope="row">Members</th>
36+
<td>
37+
{% if object.member_count %}
38+
<a href="{% url 'dcim:device_list' %}?virtual_chassis_id={{ object.pk }}">{{ object.member_count }}</a>
39+
{% else %}
40+
{{ object.member_count }}
41+
{% endif %}
42+
</td>
43+
</tr>
3444
</table>
3545
</div>
3646
</div>

0 commit comments

Comments
 (0)