diff --git a/netbox/circuits/api/views.py b/netbox/circuits/api/views.py index 1575a181b..79c4452d2 100644 --- a/netbox/circuits/api/views.py +++ b/netbox/circuits/api/views.py @@ -19,7 +19,7 @@ from . import serializers class ProviderViewSet(CustomFieldModelViewSet): queryset = Provider.objects.prefetch_related('tags').annotate( circuit_count=Count('circuits') - ) + ).order_by(*Provider._meta.ordering) serializer_class = serializers.ProviderSerializer filterset_class = filters.ProviderFilterSet @@ -41,7 +41,7 @@ class ProviderViewSet(CustomFieldModelViewSet): class CircuitTypeViewSet(ModelViewSet): queryset = CircuitType.objects.annotate( circuit_count=Count('circuits') - ) + ).order_by(*CircuitType._meta.ordering) serializer_class = serializers.CircuitTypeSerializer filterset_class = filters.CircuitTypeFilterSet diff --git a/netbox/circuits/migrations/0019_nullbooleanfield_to_booleanfield.py b/netbox/circuits/migrations/0019_nullbooleanfield_to_booleanfield.py new file mode 100644 index 000000000..c8e844284 --- /dev/null +++ b/netbox/circuits/migrations/0019_nullbooleanfield_to_booleanfield.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1b1 on 2020-07-16 15:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('circuits', '0018_standardize_description'), + ] + + operations = [ + migrations.AlterField( + model_name='circuittermination', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + ] diff --git a/netbox/circuits/models.py b/netbox/circuits/models.py index 63491ca20..9ec90d110 100644 --- a/netbox/circuits/models.py +++ b/netbox/circuits/models.py @@ -275,9 +275,10 @@ class CircuitTermination(CableTermination): blank=True, null=True ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) port_speed = models.PositiveIntegerField( verbose_name='Port speed (Kbps)' diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 55ff70327..df90a3671 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -21,7 +21,7 @@ from .models import Circuit, CircuitTermination, CircuitType, Provider # class ProviderListView(ObjectListView): - queryset = Provider.objects.annotate(count_circuits=Count('circuits')) + queryset = Provider.objects.annotate(count_circuits=Count('circuits')).order_by(*Provider._meta.ordering) filterset = filters.ProviderFilterSet filterset_form = forms.ProviderFilterForm table = tables.ProviderTable @@ -73,14 +73,14 @@ class ProviderBulkImportView(BulkImportView): class ProviderBulkEditView(BulkEditView): - queryset = Provider.objects.annotate(count_circuits=Count('circuits')) + queryset = Provider.objects.annotate(count_circuits=Count('circuits')).order_by(*Provider._meta.ordering) filterset = filters.ProviderFilterSet table = tables.ProviderTable form = forms.ProviderBulkEditForm class ProviderBulkDeleteView(BulkDeleteView): - queryset = Provider.objects.annotate(count_circuits=Count('circuits')) + queryset = Provider.objects.annotate(count_circuits=Count('circuits')).order_by(*Provider._meta.ordering) filterset = filters.ProviderFilterSet table = tables.ProviderTable @@ -90,7 +90,7 @@ class ProviderBulkDeleteView(BulkDeleteView): # class CircuitTypeListView(ObjectListView): - queryset = CircuitType.objects.annotate(circuit_count=Count('circuits')) + queryset = CircuitType.objects.annotate(circuit_count=Count('circuits')).order_by(*CircuitType._meta.ordering) table = tables.CircuitTypeTable @@ -110,7 +110,7 @@ class CircuitTypeBulkImportView(BulkImportView): class CircuitTypeBulkDeleteView(BulkDeleteView): - queryset = CircuitType.objects.annotate(circuit_count=Count('circuits')) + queryset = CircuitType.objects.annotate(circuit_count=Count('circuits')).order_by(*CircuitType._meta.ordering) table = tables.CircuitTypeTable diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index fdd58ef12..b5d68cebe 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -74,8 +74,12 @@ class CableTraceMixin(object): # class RegionViewSet(ModelViewSet): - queryset = Region.objects.annotate( - site_count=Count('sites') + queryset = Region.objects.add_related_count( + Region.objects.all(), + Site, + 'region', + 'site_count', + cumulative=True ) serializer_class = serializers.RegionSerializer filterset_class = filters.RegionFilterSet @@ -95,7 +99,7 @@ class SiteViewSet(CustomFieldModelViewSet): vlan_count=get_subquery(VLAN, 'site'), circuit_count=get_subquery(Circuit, 'terminations__site'), virtualmachine_count=get_subquery(VirtualMachine, 'cluster__site'), - ) + ).order_by(*Site._meta.ordering) serializer_class = serializers.SiteSerializer filterset_class = filters.SiteFilterSet @@ -115,9 +119,13 @@ class SiteViewSet(CustomFieldModelViewSet): # class RackGroupViewSet(ModelViewSet): - queryset = RackGroup.objects.prefetch_related('site').annotate( - rack_count=Count('racks') - ) + queryset = RackGroup.objects.add_related_count( + RackGroup.objects.all(), + Rack, + 'group', + 'rack_count', + cumulative=True + ).prefetch_related('site') serializer_class = serializers.RackGroupSerializer filterset_class = filters.RackGroupFilterSet @@ -129,7 +137,7 @@ class RackGroupViewSet(ModelViewSet): class RackRoleViewSet(ModelViewSet): queryset = RackRole.objects.annotate( rack_count=Count('racks') - ) + ).order_by(*RackRole._meta.ordering) serializer_class = serializers.RackRoleSerializer filterset_class = filters.RackRoleFilterSet @@ -144,7 +152,7 @@ class RackViewSet(CustomFieldModelViewSet): ).annotate( device_count=get_subquery(Device, 'rack'), powerfeed_count=get_subquery(PowerFeed, 'rack') - ) + ).order_by(*Rack._meta.ordering) serializer_class = serializers.RackSerializer filterset_class = filters.RackFilterSet @@ -217,7 +225,7 @@ class ManufacturerViewSet(ModelViewSet): devicetype_count=get_subquery(DeviceType, 'manufacturer'), inventoryitem_count=get_subquery(InventoryItem, 'manufacturer'), platform_count=get_subquery(Platform, 'manufacturer') - ) + ).order_by(*Manufacturer._meta.ordering) serializer_class = serializers.ManufacturerSerializer filterset_class = filters.ManufacturerFilterSet @@ -229,7 +237,7 @@ class ManufacturerViewSet(ModelViewSet): class DeviceTypeViewSet(CustomFieldModelViewSet): queryset = DeviceType.objects.prefetch_related('manufacturer', 'tags').annotate( device_count=Count('instances') - ) + ).order_by(*DeviceType._meta.ordering) serializer_class = serializers.DeviceTypeSerializer filterset_class = filters.DeviceTypeFilterSet @@ -294,7 +302,7 @@ class DeviceRoleViewSet(ModelViewSet): queryset = DeviceRole.objects.annotate( device_count=get_subquery(Device, 'device_role'), virtualmachine_count=get_subquery(VirtualMachine, 'role') - ) + ).order_by(*DeviceRole._meta.ordering) serializer_class = serializers.DeviceRoleSerializer filterset_class = filters.DeviceRoleFilterSet @@ -307,7 +315,7 @@ class PlatformViewSet(ModelViewSet): queryset = Platform.objects.annotate( device_count=get_subquery(Device, 'platform'), virtualmachine_count=get_subquery(VirtualMachine, 'platform') - ) + ).order_by(*Platform._meta.ordering) serializer_class = serializers.PlatformSerializer filterset_class = filters.PlatformFilterSet @@ -583,7 +591,7 @@ class CableViewSet(ModelViewSet): class VirtualChassisViewSet(ModelViewSet): queryset = VirtualChassis.objects.prefetch_related('tags').annotate( member_count=Count('members') - ) + ).order_by(*VirtualChassis._meta.ordering) serializer_class = serializers.VirtualChassisSerializer filterset_class = filters.VirtualChassisFilterSet @@ -597,7 +605,7 @@ class PowerPanelViewSet(ModelViewSet): 'site', 'rack_group' ).annotate( powerfeed_count=Count('powerfeeds') - ) + ).order_by(*PowerPanel._meta.ordering) serializer_class = serializers.PowerPanelSerializer filterset_class = filters.PowerPanelFilterSet diff --git a/netbox/dcim/migrations/0113_nullbooleanfield_to_booleanfield.py b/netbox/dcim/migrations/0113_nullbooleanfield_to_booleanfield.py new file mode 100644 index 000000000..b96e2dcd4 --- /dev/null +++ b/netbox/dcim/migrations/0113_nullbooleanfield_to_booleanfield.py @@ -0,0 +1,43 @@ +# Generated by Django 3.1b1 on 2020-07-16 15:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0112_standardize_components'), + ] + + operations = [ + migrations.AlterField( + model_name='consoleport', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + migrations.AlterField( + model_name='consoleserverport', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + migrations.AlterField( + model_name='interface', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + migrations.AlterField( + model_name='powerfeed', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + migrations.AlterField( + model_name='poweroutlet', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + migrations.AlterField( + model_name='powerport', + name='connection_status', + field=models.BooleanField(blank=True, null=True), + ), + ] diff --git a/netbox/dcim/migrations/0114_update_jsonfield.py b/netbox/dcim/migrations/0114_update_jsonfield.py new file mode 100644 index 000000000..5a971bced --- /dev/null +++ b/netbox/dcim/migrations/0114_update_jsonfield.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1b1 on 2020-07-16 16:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0113_nullbooleanfield_to_booleanfield'), + ] + + operations = [ + migrations.AlterField( + model_name='device', + name='local_context_data', + field=models.JSONField(blank=True, null=True), + ), + migrations.AlterField( + model_name='platform', + name='napalm_args', + field=models.JSONField(blank=True, null=True), + ), + ] diff --git a/netbox/dcim/models/__init__.py b/netbox/dcim/models/__init__.py index 9b1019990..5e3f57e0e 100644 --- a/netbox/dcim/models/__init__.py +++ b/netbox/dcim/models/__init__.py @@ -6,7 +6,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType -from django.contrib.postgres.fields import ArrayField, JSONField +from django.contrib.postgres.fields import ArrayField from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models @@ -1280,7 +1280,7 @@ class Platform(ChangeLoggedModel): verbose_name='NAPALM driver', help_text='The name of the NAPALM driver to use when interacting with devices' ) - napalm_args = JSONField( + napalm_args = models.JSONField( blank=True, null=True, verbose_name='NAPALM arguments', @@ -1905,9 +1905,10 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel): blank=True, null=True ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) name = models.CharField( max_length=50 diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 1ebb0c4d5..6764f8bcf 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -264,9 +264,10 @@ class ConsolePort(CableTermination, ComponentModel): blank=True, null=True ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) tags = TaggableManager(through=TaggedItem) @@ -304,9 +305,10 @@ class ConsoleServerPort(CableTermination, ComponentModel): blank=True, help_text='Physical port type' ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) tags = TaggableManager(through=TaggedItem) @@ -370,9 +372,10 @@ class PowerPort(CableTermination, ComponentModel): blank=True, null=True ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) tags = TaggableManager(through=TaggedItem) @@ -505,9 +508,10 @@ class PowerOutlet(CableTermination, ComponentModel): blank=True, help_text="Phase (for three-phase feeds)" ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) tags = TaggableManager(through=TaggedItem) @@ -598,9 +602,10 @@ class Interface(CableTermination, ComponentModel, BaseInterface): blank=True, null=True ) - connection_status = models.NullBooleanField( + connection_status = models.BooleanField( choices=CONNECTION_STATUS_CHOICES, - blank=True + blank=True, + null=True ) lag = models.ForeignKey( to='self', diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 889b4d94e..2216bafd3 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -133,7 +133,13 @@ class RegionBulkImportView(BulkImportView): class RegionBulkDeleteView(BulkDeleteView): - queryset = Region.objects.all() + queryset = Region.objects.add_related_count( + Region.objects.all(), + Site, + 'region', + 'site_count', + cumulative=True + ) filterset = filters.RegionFilterSet table = tables.RegionTable @@ -238,7 +244,13 @@ class RackGroupBulkImportView(BulkImportView): class RackGroupBulkDeleteView(BulkDeleteView): - queryset = RackGroup.objects.prefetch_related('site').annotate(rack_count=Count('racks')) + queryset = RackGroup.objects.add_related_count( + RackGroup.objects.all(), + Rack, + 'group', + 'rack_count', + cumulative=True + ).prefetch_related('site') filterset = filters.RackGroupFilterSet table = tables.RackGroupTable @@ -248,7 +260,7 @@ class RackGroupBulkDeleteView(BulkDeleteView): # class RackRoleListView(ObjectListView): - queryset = RackRole.objects.annotate(rack_count=Count('racks')) + queryset = RackRole.objects.annotate(rack_count=Count('racks')).order_by(*RackRole._meta.ordering) table = tables.RackRoleTable @@ -268,7 +280,7 @@ class RackRoleBulkImportView(BulkImportView): class RackRoleBulkDeleteView(BulkDeleteView): - queryset = RackRole.objects.annotate(rack_count=Count('racks')) + queryset = RackRole.objects.annotate(rack_count=Count('racks')).order_by(*RackRole._meta.ordering) table = tables.RackRoleTable @@ -281,7 +293,7 @@ class RackListView(ObjectListView): 'site', 'group', 'tenant', 'role', 'devices__device_type' ).annotate( device_count=Count('devices') - ) + ).order_by(*Rack._meta.ordering) filterset = filters.RackFilterSet filterset_form = forms.RackFilterForm table = tables.RackDetailTable @@ -465,7 +477,7 @@ class ManufacturerListView(ObjectListView): devicetype_count=Count('device_types', distinct=True), inventoryitem_count=Count('inventory_items', distinct=True), platform_count=Count('platforms', distinct=True), - ) + ).order_by(*Manufacturer._meta.ordering) table = tables.ManufacturerTable @@ -485,7 +497,9 @@ class ManufacturerBulkImportView(BulkImportView): class ManufacturerBulkDeleteView(BulkDeleteView): - queryset = Manufacturer.objects.annotate(devicetype_count=Count('device_types')) + queryset = Manufacturer.objects.annotate( + devicetype_count=Count('device_types') + ).order_by(*Manufacturer._meta.ordering) table = tables.ManufacturerTable @@ -494,7 +508,9 @@ class ManufacturerBulkDeleteView(BulkDeleteView): # class DeviceTypeListView(ObjectListView): - queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances')) + queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( + instance_count=Count('instances') + ).order_by(*DeviceType._meta.ordering) filterset = filters.DeviceTypeFilterSet filterset_form = forms.DeviceTypeFilterForm table = tables.DeviceTypeTable @@ -602,14 +618,18 @@ class DeviceTypeImportView(ObjectImportView): class DeviceTypeBulkEditView(BulkEditView): - queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances')) + queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( + instance_count=Count('instances') + ).order_by(*DeviceType._meta.ordering) filterset = filters.DeviceTypeFilterSet table = tables.DeviceTypeTable form = forms.DeviceTypeBulkEditForm class DeviceTypeBulkDeleteView(BulkDeleteView): - queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances')) + queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( + instance_count=Count('instances') + ).order_by(*DeviceType._meta.ordering) filterset = filters.DeviceTypeFilterSet table = tables.DeviceTypeTable @@ -2152,7 +2172,9 @@ class InterfaceConnectionsListView(ObjectListView): # class VirtualChassisListView(ObjectListView): - queryset = VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members')) + queryset = VirtualChassis.objects.prefetch_related('master').annotate( + member_count=Count('members') + ).order_by(*VirtualChassis._meta.ordering) table = tables.VirtualChassisTable filterset = filters.VirtualChassisFilterSet filterset_form = forms.VirtualChassisFilterForm @@ -2385,7 +2407,7 @@ class PowerPanelListView(ObjectListView): 'site', 'rack_group' ).annotate( powerfeed_count=Count('powerfeeds') - ) + ).order_by(*PowerPanel._meta.ordering) filterset = filters.PowerPanelFilterSet filterset_form = forms.PowerPanelFilterForm table = tables.PowerPanelTable @@ -2437,7 +2459,7 @@ class PowerPanelBulkDeleteView(BulkDeleteView): 'site', 'rack_group' ).annotate( rack_count=Count('powerfeeds') - ) + ).order_by(*PowerPanel._meta.ordering) filterset = filters.PowerPanelFilterSet table = tables.PowerPanelTable diff --git a/netbox/extras/migrations/0046_update_jsonfield.py b/netbox/extras/migrations/0046_update_jsonfield.py new file mode 100644 index 000000000..a06302840 --- /dev/null +++ b/netbox/extras/migrations/0046_update_jsonfield.py @@ -0,0 +1,28 @@ +# Generated by Django 3.1b1 on 2020-07-16 16:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0045_configcontext_changelog'), + ] + + operations = [ + migrations.AlterField( + model_name='configcontext', + name='data', + field=models.JSONField(), + ), + migrations.AlterField( + model_name='jobresult', + name='data', + field=models.JSONField(blank=True, null=True), + ), + migrations.AlterField( + model_name='objectchange', + name='object_data', + field=models.JSONField(editable=False), + ), + ] diff --git a/netbox/extras/models/change_logging.py b/netbox/extras/models/change_logging.py index 3260c5302..bec8e2b75 100644 --- a/netbox/extras/models/change_logging.py +++ b/netbox/extras/models/change_logging.py @@ -1,7 +1,6 @@ from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType -from django.contrib.postgres.fields import JSONField from django.db import models from django.urls import reverse @@ -104,7 +103,7 @@ class ObjectChange(models.Model): max_length=200, editable=False ) - object_data = JSONField( + object_data = models.JSONField( editable=False ) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index edd13a123..fcfcfefb3 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -5,7 +5,6 @@ from collections import OrderedDict from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType -from django.contrib.postgres.fields import JSONField from django.core.validators import ValidationError from django.db import models from django.http import HttpResponse @@ -499,7 +498,7 @@ class ConfigContext(ChangeLoggedModel): related_name='+', blank=True ) - data = JSONField() + data = models.JSONField() objects = ConfigContextQuerySet.as_manager() @@ -526,7 +525,7 @@ class ConfigContextModel(models.Model): A model which includes local configuration context data. This local data will override any inherited data from ConfigContexts. """ - local_context_data = JSONField( + local_context_data = models.JSONField( blank=True, null=True, ) @@ -627,7 +626,7 @@ class JobResult(models.Model): choices=JobResultStatusChoices, default=JobResultStatusChoices.STATUS_PENDING ) - data = JSONField( + data = models.JSONField( null=True, blank=True ) diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index dd096c392..9c8ef7b09 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -11,7 +11,7 @@ from django import forms from django.conf import settings from django.core.validators import RegexValidator from django.db import transaction -from django.utils.decorators import classproperty +from django.utils.functional import classproperty from django_rq import job from extras.api.serializers import ScriptOutputSerializer diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index 77ac36683..80b29a76e 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -24,7 +24,7 @@ class VRFViewSet(CustomFieldModelViewSet): queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate( ipaddress_count=get_subquery(IPAddress, 'vrf'), prefix_count=get_subquery(Prefix, 'vrf') - ) + ).order_by(*VRF._meta.ordering) serializer_class = serializers.VRFSerializer filterset_class = filters.VRFFilterSet @@ -36,7 +36,7 @@ class VRFViewSet(CustomFieldModelViewSet): class RIRViewSet(ModelViewSet): queryset = RIR.objects.annotate( aggregate_count=Count('aggregates') - ) + ).order_by(*RIR._meta.ordering) serializer_class = serializers.RIRSerializer filterset_class = filters.RIRFilterSet @@ -59,7 +59,7 @@ class RoleViewSet(ModelViewSet): queryset = Role.objects.annotate( prefix_count=get_subquery(Prefix, 'role'), vlan_count=get_subquery(VLAN, 'role') - ) + ).order_by(*Role._meta.ordering) serializer_class = serializers.RoleSerializer filterset_class = filters.RoleFilterSet @@ -246,7 +246,7 @@ class IPAddressViewSet(CustomFieldModelViewSet): class VLANGroupViewSet(ModelViewSet): queryset = VLANGroup.objects.prefetch_related('site').annotate( vlan_count=Count('vlans') - ) + ).order_by(*VLANGroup._meta.ordering) serializer_class = serializers.VLANGroupSerializer filterset_class = filters.VLANGroupFilterSet @@ -260,7 +260,7 @@ class VLANViewSet(CustomFieldModelViewSet): 'site', 'group', 'tenant', 'role', 'tags' ).annotate( prefix_count=get_subquery(Prefix, 'vlan') - ) + ).order_by(*VLAN._meta.ordering) serializer_class = serializers.VLANSerializer filterset_class = filters.VLANFilterSet diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 8a9c647f0..2a4188df4 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -78,7 +78,7 @@ class VRFBulkDeleteView(BulkDeleteView): # class RIRListView(ObjectListView): - queryset = RIR.objects.annotate(aggregate_count=Count('aggregates')) + queryset = RIR.objects.annotate(aggregate_count=Count('aggregates')).order_by(*RIR._meta.ordering) filterset = filters.RIRFilterSet filterset_form = forms.RIRFilterForm table = tables.RIRDetailTable @@ -171,7 +171,7 @@ class RIRBulkImportView(BulkImportView): class RIRBulkDeleteView(BulkDeleteView): - queryset = RIR.objects.annotate(aggregate_count=Count('aggregates')) + queryset = RIR.objects.annotate(aggregate_count=Count('aggregates')).order_by(*RIR._meta.ordering) filterset = filters.RIRFilterSet table = tables.RIRTable @@ -183,7 +183,7 @@ class RIRBulkDeleteView(BulkDeleteView): class AggregateListView(ObjectListView): queryset = Aggregate.objects.prefetch_related('rir').annotate( child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) - ) + ).order_by(*Aggregate._meta.ordering) filterset = filters.AggregateFilterSet filterset_form = forms.AggregateFilterForm table = tables.AggregateDetailTable @@ -650,7 +650,9 @@ class IPAddressBulkDeleteView(BulkDeleteView): # class VLANGroupListView(ObjectListView): - queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans')) + queryset = VLANGroup.objects.prefetch_related('site').annotate( + vlan_count=Count('vlans') + ).order_by(*VLANGroup._meta.ordering) filterset = filters.VLANGroupFilterSet filterset_form = forms.VLANGroupFilterForm table = tables.VLANGroupTable @@ -672,7 +674,9 @@ class VLANGroupBulkImportView(BulkImportView): class VLANGroupBulkDeleteView(BulkDeleteView): - queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans')) + queryset = VLANGroup.objects.prefetch_related('site').annotate( + vlan_count=Count('vlans') + ).order_by(*VLANGroup._meta.ordering) filterset = filters.VLANGroupFilterSet table = tables.VLANGroupTable diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 548173a32..a743947fe 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -46,7 +46,9 @@ SEARCH_MAX_RESULTS = 15 SEARCH_TYPES = OrderedDict(( # Circuits ('provider', { - 'queryset': Provider.objects.annotate(count_circuits=Count('circuits')), + 'queryset': Provider.objects.annotate( + count_circuits=Count('circuits') + ).order_by(*Provider._meta.ordering), 'filterset': ProviderFilterSet, 'table': ProviderTable, 'url': 'circuits:provider_list', @@ -73,13 +75,17 @@ SEARCH_TYPES = OrderedDict(( 'url': 'dcim:rack_list', }), ('rackgroup', { - 'queryset': RackGroup.objects.prefetch_related('site').annotate(rack_count=Count('racks')), + 'queryset': RackGroup.objects.prefetch_related('site').annotate( + rack_count=Count('racks') + ).order_by(*RackGroup._meta.ordering), 'filterset': RackGroupFilterSet, 'table': RackGroupTable, 'url': 'dcim:rackgroup_list', }), ('devicetype', { - 'queryset': DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances')), + 'queryset': DeviceType.objects.prefetch_related('manufacturer').annotate( + instance_count=Count('instances') + ).order_by(*DeviceType._meta.ordering), 'filterset': DeviceTypeFilterSet, 'table': DeviceTypeTable, 'url': 'dcim:devicetype_list', @@ -93,7 +99,9 @@ SEARCH_TYPES = OrderedDict(( 'url': 'dcim:device_list', }), ('virtualchassis', { - 'queryset': VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members')), + 'queryset': VirtualChassis.objects.prefetch_related('master').annotate( + member_count=Count('members') + ).order_by(*VirtualChassis._meta.ordering), 'filterset': VirtualChassisFilterSet, 'table': VirtualChassisTable, 'url': 'dcim:virtualchassis_list', diff --git a/netbox/secrets/api/views.py b/netbox/secrets/api/views.py index 9e330b782..3ad87a8ff 100644 --- a/netbox/secrets/api/views.py +++ b/netbox/secrets/api/views.py @@ -27,7 +27,7 @@ ERR_PRIVKEY_INVALID = "Invalid private key." class SecretRoleViewSet(ModelViewSet): queryset = SecretRole.objects.annotate( secret_count=Count('secrets') - ) + ).order_by(*SecretRole._meta.ordering) serializer_class = serializers.SecretRoleSerializer filterset_class = filters.SecretRoleFilterSet diff --git a/netbox/secrets/views.py b/netbox/secrets/views.py index e9ea1835f..2872616b8 100644 --- a/netbox/secrets/views.py +++ b/netbox/secrets/views.py @@ -29,7 +29,7 @@ def get_session_key(request): # class SecretRoleListView(ObjectListView): - queryset = SecretRole.objects.annotate(secret_count=Count('secrets')) + queryset = SecretRole.objects.annotate(secret_count=Count('secrets')).order_by(*SecretRole._meta.ordering) table = tables.SecretRoleTable @@ -49,7 +49,7 @@ class SecretRoleBulkImportView(BulkImportView): class SecretRoleBulkDeleteView(BulkDeleteView): - queryset = SecretRole.objects.annotate(secret_count=Count('secrets')) + queryset = SecretRole.objects.annotate(secret_count=Count('secrets')).order_by(*SecretRole._meta.ordering) table = tables.SecretRoleTable diff --git a/netbox/templates/inc/paginator.html b/netbox/templates/inc/paginator.html index c0baef070..50d7e06d3 100644 --- a/netbox/templates/inc/paginator.html +++ b/netbox/templates/inc/paginator.html @@ -9,7 +9,7 @@ {% endif %} {% for p in page.smart_pages %} {% if p %} -