mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-18 04:56:29 -06:00
Closes #10197: Add a cached counter field for virtual chassis members
This commit is contained in:
parent
9b6e32896d
commit
daa8f71bb6
@ -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',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -579,9 +579,7 @@ class CableTerminationViewSet(NetBoxModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VirtualChassisViewSet(NetBoxModelViewSet):
|
class VirtualChassisViewSet(NetBoxModelViewSet):
|
||||||
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
|
queryset = VirtualChassis.objects.prefetch_related('tags')
|
||||||
member_count=count_related(Device, 'virtual_chassis')
|
|
||||||
)
|
|
||||||
serializer_class = serializers.VirtualChassisSerializer
|
serializer_class = serializers.VirtualChassisSerializer
|
||||||
filterset_class = filtersets.VirtualChassisFilterSet
|
filterset_class = filtersets.VirtualChassisFilterSet
|
||||||
brief_prefetch_fields = ['master']
|
brief_prefetch_fields = ['master']
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
),
|
||||||
|
]
|
@ -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'
|
||||||
|
@ -3227,9 +3227,7 @@ class InterfaceConnectionsListView(generic.ObjectListView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VirtualChassisListView(generic.ObjectListView):
|
class VirtualChassisListView(generic.ObjectListView):
|
||||||
queryset = VirtualChassis.objects.annotate(
|
queryset = VirtualChassis.objects.all()
|
||||||
member_count=count_related(Device, 'virtual_chassis')
|
|
||||||
)
|
|
||||||
table = tables.VirtualChassisTable
|
table = tables.VirtualChassisTable
|
||||||
filterset = filtersets.VirtualChassisFilterSet
|
filterset = filtersets.VirtualChassisFilterSet
|
||||||
filterset_form = forms.VirtualChassisFilterForm
|
filterset_form = forms.VirtualChassisFilterForm
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user