Просмотр исходного кода

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

Jeremy Stretch 2 лет назад
Родитель
Сommit
daa8f71bb6

+ 3 - 1
netbox/dcim/api/serializers.py

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

+ 1 - 3
netbox/dcim/api/views.py

@@ -579,9 +579,7 @@ class CableTerminationViewSet(NetBoxModelViewSet):
 #
 #
 
 
 class VirtualChassisViewSet(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
     serializer_class = serializers.VirtualChassisSerializer
     filterset_class = filtersets.VirtualChassisFilterSet
     filterset_class = filtersets.VirtualChassisFilterSet
     brief_prefetch_fields = ['master']
     brief_prefetch_fields = ['master']

+ 2 - 2
netbox/dcim/apps.py

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

+ 35 - 0
netbox/dcim/migrations/0177_virtual_chassis_member_counter.py

@@ -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
+        ),
+    ]

+ 8 - 1
netbox/dcim/models/devices.py

@@ -22,6 +22,7 @@ from netbox.config import ConfigItem
 from netbox.models import OrganizationalModel, PrimaryModel
 from netbox.models import OrganizationalModel, PrimaryModel
 from utilities.choices import ColorChoices
 from utilities.choices import ColorChoices
 from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField
 from utilities.fields import ColorField, CounterCacheField, NaturalOrderingField
+from utilities.tracking import TrackingModelMixin
 from .device_components import *
 from .device_components import *
 from .mixins import WeightMixin
 from .mixins import WeightMixin
 
 
@@ -469,7 +470,7 @@ def update_interface_bridges(device, interface_templates, module=None):
             interface.save()
             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,
     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.
     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
         blank=True
     )
     )
 
 
+    # Counter fields
+    member_count = CounterCacheField(
+        to_model='dcim.Device',
+        to_field='virtual_chassis'
+    )
+
     class Meta:
     class Meta:
         ordering = ['name']
         ordering = ['name']
         verbose_name_plural = 'virtual chassis'
         verbose_name_plural = 'virtual chassis'

+ 1 - 3
netbox/dcim/views.py

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

+ 10 - 0
netbox/templates/dcim/virtualchassis.html

@@ -31,6 +31,16 @@
             <th scope="row">Description</th>
             <th scope="row">Description</th>
             <td>{{ object.description|placeholder }}</td>
             <td>{{ object.description|placeholder }}</td>
           </tr>
           </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>
         </table>
       </div>
       </div>
     </div>
     </div>