mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 17:38:37 -06:00
Merge pull request #4861 from netbox-community/django-31
Upgrade to Django 3.1 (v2.9)
This commit is contained in:
commit
de6202c160
@ -19,7 +19,7 @@ from . import serializers
|
|||||||
class ProviderViewSet(CustomFieldModelViewSet):
|
class ProviderViewSet(CustomFieldModelViewSet):
|
||||||
queryset = Provider.objects.prefetch_related('tags').annotate(
|
queryset = Provider.objects.prefetch_related('tags').annotate(
|
||||||
circuit_count=Count('circuits')
|
circuit_count=Count('circuits')
|
||||||
)
|
).order_by(*Provider._meta.ordering)
|
||||||
serializer_class = serializers.ProviderSerializer
|
serializer_class = serializers.ProviderSerializer
|
||||||
filterset_class = filters.ProviderFilterSet
|
filterset_class = filters.ProviderFilterSet
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class ProviderViewSet(CustomFieldModelViewSet):
|
|||||||
class CircuitTypeViewSet(ModelViewSet):
|
class CircuitTypeViewSet(ModelViewSet):
|
||||||
queryset = CircuitType.objects.annotate(
|
queryset = CircuitType.objects.annotate(
|
||||||
circuit_count=Count('circuits')
|
circuit_count=Count('circuits')
|
||||||
)
|
).order_by(*CircuitType._meta.ordering)
|
||||||
serializer_class = serializers.CircuitTypeSerializer
|
serializer_class = serializers.CircuitTypeSerializer
|
||||||
filterset_class = filters.CircuitTypeFilterSet
|
filterset_class = filters.CircuitTypeFilterSet
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
@ -275,9 +275,10 @@ class CircuitTermination(CableTermination):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
port_speed = models.PositiveIntegerField(
|
port_speed = models.PositiveIntegerField(
|
||||||
verbose_name='Port speed (Kbps)'
|
verbose_name='Port speed (Kbps)'
|
||||||
|
@ -21,7 +21,7 @@ from .models import Circuit, CircuitTermination, CircuitType, Provider
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ProviderListView(ObjectListView):
|
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 = filters.ProviderFilterSet
|
||||||
filterset_form = forms.ProviderFilterForm
|
filterset_form = forms.ProviderFilterForm
|
||||||
table = tables.ProviderTable
|
table = tables.ProviderTable
|
||||||
@ -73,14 +73,14 @@ class ProviderBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class ProviderBulkEditView(BulkEditView):
|
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
|
filterset = filters.ProviderFilterSet
|
||||||
table = tables.ProviderTable
|
table = tables.ProviderTable
|
||||||
form = forms.ProviderBulkEditForm
|
form = forms.ProviderBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class ProviderBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.ProviderFilterSet
|
||||||
table = tables.ProviderTable
|
table = tables.ProviderTable
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class ProviderBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class CircuitTypeListView(ObjectListView):
|
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
|
table = tables.CircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ class CircuitTypeBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class CircuitTypeBulkDeleteView(BulkDeleteView):
|
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
|
table = tables.CircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,8 +74,12 @@ class CableTraceMixin(object):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RegionViewSet(ModelViewSet):
|
class RegionViewSet(ModelViewSet):
|
||||||
queryset = Region.objects.annotate(
|
queryset = Region.objects.add_related_count(
|
||||||
site_count=Count('sites')
|
Region.objects.all(),
|
||||||
|
Site,
|
||||||
|
'region',
|
||||||
|
'site_count',
|
||||||
|
cumulative=True
|
||||||
)
|
)
|
||||||
serializer_class = serializers.RegionSerializer
|
serializer_class = serializers.RegionSerializer
|
||||||
filterset_class = filters.RegionFilterSet
|
filterset_class = filters.RegionFilterSet
|
||||||
@ -95,7 +99,7 @@ class SiteViewSet(CustomFieldModelViewSet):
|
|||||||
vlan_count=get_subquery(VLAN, 'site'),
|
vlan_count=get_subquery(VLAN, 'site'),
|
||||||
circuit_count=get_subquery(Circuit, 'terminations__site'),
|
circuit_count=get_subquery(Circuit, 'terminations__site'),
|
||||||
virtualmachine_count=get_subquery(VirtualMachine, 'cluster__site'),
|
virtualmachine_count=get_subquery(VirtualMachine, 'cluster__site'),
|
||||||
)
|
).order_by(*Site._meta.ordering)
|
||||||
serializer_class = serializers.SiteSerializer
|
serializer_class = serializers.SiteSerializer
|
||||||
filterset_class = filters.SiteFilterSet
|
filterset_class = filters.SiteFilterSet
|
||||||
|
|
||||||
@ -115,9 +119,13 @@ class SiteViewSet(CustomFieldModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackGroupViewSet(ModelViewSet):
|
class RackGroupViewSet(ModelViewSet):
|
||||||
queryset = RackGroup.objects.prefetch_related('site').annotate(
|
queryset = RackGroup.objects.add_related_count(
|
||||||
rack_count=Count('racks')
|
RackGroup.objects.all(),
|
||||||
)
|
Rack,
|
||||||
|
'group',
|
||||||
|
'rack_count',
|
||||||
|
cumulative=True
|
||||||
|
).prefetch_related('site')
|
||||||
serializer_class = serializers.RackGroupSerializer
|
serializer_class = serializers.RackGroupSerializer
|
||||||
filterset_class = filters.RackGroupFilterSet
|
filterset_class = filters.RackGroupFilterSet
|
||||||
|
|
||||||
@ -129,7 +137,7 @@ class RackGroupViewSet(ModelViewSet):
|
|||||||
class RackRoleViewSet(ModelViewSet):
|
class RackRoleViewSet(ModelViewSet):
|
||||||
queryset = RackRole.objects.annotate(
|
queryset = RackRole.objects.annotate(
|
||||||
rack_count=Count('racks')
|
rack_count=Count('racks')
|
||||||
)
|
).order_by(*RackRole._meta.ordering)
|
||||||
serializer_class = serializers.RackRoleSerializer
|
serializer_class = serializers.RackRoleSerializer
|
||||||
filterset_class = filters.RackRoleFilterSet
|
filterset_class = filters.RackRoleFilterSet
|
||||||
|
|
||||||
@ -144,7 +152,7 @@ class RackViewSet(CustomFieldModelViewSet):
|
|||||||
).annotate(
|
).annotate(
|
||||||
device_count=get_subquery(Device, 'rack'),
|
device_count=get_subquery(Device, 'rack'),
|
||||||
powerfeed_count=get_subquery(PowerFeed, 'rack')
|
powerfeed_count=get_subquery(PowerFeed, 'rack')
|
||||||
)
|
).order_by(*Rack._meta.ordering)
|
||||||
serializer_class = serializers.RackSerializer
|
serializer_class = serializers.RackSerializer
|
||||||
filterset_class = filters.RackFilterSet
|
filterset_class = filters.RackFilterSet
|
||||||
|
|
||||||
@ -217,7 +225,7 @@ class ManufacturerViewSet(ModelViewSet):
|
|||||||
devicetype_count=get_subquery(DeviceType, 'manufacturer'),
|
devicetype_count=get_subquery(DeviceType, 'manufacturer'),
|
||||||
inventoryitem_count=get_subquery(InventoryItem, 'manufacturer'),
|
inventoryitem_count=get_subquery(InventoryItem, 'manufacturer'),
|
||||||
platform_count=get_subquery(Platform, 'manufacturer')
|
platform_count=get_subquery(Platform, 'manufacturer')
|
||||||
)
|
).order_by(*Manufacturer._meta.ordering)
|
||||||
serializer_class = serializers.ManufacturerSerializer
|
serializer_class = serializers.ManufacturerSerializer
|
||||||
filterset_class = filters.ManufacturerFilterSet
|
filterset_class = filters.ManufacturerFilterSet
|
||||||
|
|
||||||
@ -229,7 +237,7 @@ class ManufacturerViewSet(ModelViewSet):
|
|||||||
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
||||||
queryset = DeviceType.objects.prefetch_related('manufacturer', 'tags').annotate(
|
queryset = DeviceType.objects.prefetch_related('manufacturer', 'tags').annotate(
|
||||||
device_count=Count('instances')
|
device_count=Count('instances')
|
||||||
)
|
).order_by(*DeviceType._meta.ordering)
|
||||||
serializer_class = serializers.DeviceTypeSerializer
|
serializer_class = serializers.DeviceTypeSerializer
|
||||||
filterset_class = filters.DeviceTypeFilterSet
|
filterset_class = filters.DeviceTypeFilterSet
|
||||||
|
|
||||||
@ -294,7 +302,7 @@ class DeviceRoleViewSet(ModelViewSet):
|
|||||||
queryset = DeviceRole.objects.annotate(
|
queryset = DeviceRole.objects.annotate(
|
||||||
device_count=get_subquery(Device, 'device_role'),
|
device_count=get_subquery(Device, 'device_role'),
|
||||||
virtualmachine_count=get_subquery(VirtualMachine, 'role')
|
virtualmachine_count=get_subquery(VirtualMachine, 'role')
|
||||||
)
|
).order_by(*DeviceRole._meta.ordering)
|
||||||
serializer_class = serializers.DeviceRoleSerializer
|
serializer_class = serializers.DeviceRoleSerializer
|
||||||
filterset_class = filters.DeviceRoleFilterSet
|
filterset_class = filters.DeviceRoleFilterSet
|
||||||
|
|
||||||
@ -307,7 +315,7 @@ class PlatformViewSet(ModelViewSet):
|
|||||||
queryset = Platform.objects.annotate(
|
queryset = Platform.objects.annotate(
|
||||||
device_count=get_subquery(Device, 'platform'),
|
device_count=get_subquery(Device, 'platform'),
|
||||||
virtualmachine_count=get_subquery(VirtualMachine, 'platform')
|
virtualmachine_count=get_subquery(VirtualMachine, 'platform')
|
||||||
)
|
).order_by(*Platform._meta.ordering)
|
||||||
serializer_class = serializers.PlatformSerializer
|
serializer_class = serializers.PlatformSerializer
|
||||||
filterset_class = filters.PlatformFilterSet
|
filterset_class = filters.PlatformFilterSet
|
||||||
|
|
||||||
@ -583,7 +591,7 @@ class CableViewSet(ModelViewSet):
|
|||||||
class VirtualChassisViewSet(ModelViewSet):
|
class VirtualChassisViewSet(ModelViewSet):
|
||||||
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
|
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
|
||||||
member_count=Count('members')
|
member_count=Count('members')
|
||||||
)
|
).order_by(*VirtualChassis._meta.ordering)
|
||||||
serializer_class = serializers.VirtualChassisSerializer
|
serializer_class = serializers.VirtualChassisSerializer
|
||||||
filterset_class = filters.VirtualChassisFilterSet
|
filterset_class = filters.VirtualChassisFilterSet
|
||||||
|
|
||||||
@ -597,7 +605,7 @@ class PowerPanelViewSet(ModelViewSet):
|
|||||||
'site', 'rack_group'
|
'site', 'rack_group'
|
||||||
).annotate(
|
).annotate(
|
||||||
powerfeed_count=Count('powerfeeds')
|
powerfeed_count=Count('powerfeeds')
|
||||||
)
|
).order_by(*PowerPanel._meta.ordering)
|
||||||
serializer_class = serializers.PowerPanelSerializer
|
serializer_class = serializers.PowerPanelSerializer
|
||||||
filterset_class = filters.PowerPanelFilterSet
|
filterset_class = filters.PowerPanelFilterSet
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
23
netbox/dcim/migrations/0114_update_jsonfield.py
Normal file
23
netbox/dcim/migrations/0114_update_jsonfield.py
Normal file
@ -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),
|
||||||
|
),
|
||||||
|
]
|
@ -6,7 +6,7 @@ from django.conf import settings
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||||
from django.contrib.contenttypes.models import ContentType
|
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.exceptions import ObjectDoesNotExist, ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@ -1280,7 +1280,7 @@ class Platform(ChangeLoggedModel):
|
|||||||
verbose_name='NAPALM driver',
|
verbose_name='NAPALM driver',
|
||||||
help_text='The name of the NAPALM driver to use when interacting with devices'
|
help_text='The name of the NAPALM driver to use when interacting with devices'
|
||||||
)
|
)
|
||||||
napalm_args = JSONField(
|
napalm_args = models.JSONField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name='NAPALM arguments',
|
verbose_name='NAPALM arguments',
|
||||||
@ -1905,9 +1905,10 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=50
|
max_length=50
|
||||||
|
@ -264,9 +264,10 @@ class ConsolePort(CableTermination, ComponentModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
@ -304,9 +305,10 @@ class ConsoleServerPort(CableTermination, ComponentModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
help_text='Physical port type'
|
help_text='Physical port type'
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
@ -370,9 +372,10 @@ class PowerPort(CableTermination, ComponentModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
@ -505,9 +508,10 @@ class PowerOutlet(CableTermination, ComponentModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
help_text="Phase (for three-phase feeds)"
|
help_text="Phase (for three-phase feeds)"
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
@ -598,9 +602,10 @@ class Interface(CableTermination, ComponentModel, BaseInterface):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.BooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
lag = models.ForeignKey(
|
lag = models.ForeignKey(
|
||||||
to='self',
|
to='self',
|
||||||
|
@ -133,7 +133,13 @@ class RegionBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class RegionBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.RegionFilterSet
|
||||||
table = tables.RegionTable
|
table = tables.RegionTable
|
||||||
|
|
||||||
@ -238,7 +244,13 @@ class RackGroupBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class RackGroupBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.RackGroupFilterSet
|
||||||
table = tables.RackGroupTable
|
table = tables.RackGroupTable
|
||||||
|
|
||||||
@ -248,7 +260,7 @@ class RackGroupBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RackRoleListView(ObjectListView):
|
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
|
table = tables.RackRoleTable
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +280,7 @@ class RackRoleBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class RackRoleBulkDeleteView(BulkDeleteView):
|
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
|
table = tables.RackRoleTable
|
||||||
|
|
||||||
|
|
||||||
@ -281,7 +293,7 @@ class RackListView(ObjectListView):
|
|||||||
'site', 'group', 'tenant', 'role', 'devices__device_type'
|
'site', 'group', 'tenant', 'role', 'devices__device_type'
|
||||||
).annotate(
|
).annotate(
|
||||||
device_count=Count('devices')
|
device_count=Count('devices')
|
||||||
)
|
).order_by(*Rack._meta.ordering)
|
||||||
filterset = filters.RackFilterSet
|
filterset = filters.RackFilterSet
|
||||||
filterset_form = forms.RackFilterForm
|
filterset_form = forms.RackFilterForm
|
||||||
table = tables.RackDetailTable
|
table = tables.RackDetailTable
|
||||||
@ -465,7 +477,7 @@ class ManufacturerListView(ObjectListView):
|
|||||||
devicetype_count=Count('device_types', distinct=True),
|
devicetype_count=Count('device_types', distinct=True),
|
||||||
inventoryitem_count=Count('inventory_items', distinct=True),
|
inventoryitem_count=Count('inventory_items', distinct=True),
|
||||||
platform_count=Count('platforms', distinct=True),
|
platform_count=Count('platforms', distinct=True),
|
||||||
)
|
).order_by(*Manufacturer._meta.ordering)
|
||||||
table = tables.ManufacturerTable
|
table = tables.ManufacturerTable
|
||||||
|
|
||||||
|
|
||||||
@ -485,7 +497,9 @@ class ManufacturerBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class ManufacturerBulkDeleteView(BulkDeleteView):
|
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
|
table = tables.ManufacturerTable
|
||||||
|
|
||||||
|
|
||||||
@ -494,7 +508,9 @@ class ManufacturerBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class DeviceTypeListView(ObjectListView):
|
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 = filters.DeviceTypeFilterSet
|
||||||
filterset_form = forms.DeviceTypeFilterForm
|
filterset_form = forms.DeviceTypeFilterForm
|
||||||
table = tables.DeviceTypeTable
|
table = tables.DeviceTypeTable
|
||||||
@ -602,14 +618,18 @@ class DeviceTypeImportView(ObjectImportView):
|
|||||||
|
|
||||||
|
|
||||||
class DeviceTypeBulkEditView(BulkEditView):
|
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
|
filterset = filters.DeviceTypeFilterSet
|
||||||
table = tables.DeviceTypeTable
|
table = tables.DeviceTypeTable
|
||||||
form = forms.DeviceTypeBulkEditForm
|
form = forms.DeviceTypeBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.DeviceTypeFilterSet
|
||||||
table = tables.DeviceTypeTable
|
table = tables.DeviceTypeTable
|
||||||
|
|
||||||
@ -2152,7 +2172,9 @@ class InterfaceConnectionsListView(ObjectListView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VirtualChassisListView(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
|
table = tables.VirtualChassisTable
|
||||||
filterset = filters.VirtualChassisFilterSet
|
filterset = filters.VirtualChassisFilterSet
|
||||||
filterset_form = forms.VirtualChassisFilterForm
|
filterset_form = forms.VirtualChassisFilterForm
|
||||||
@ -2385,7 +2407,7 @@ class PowerPanelListView(ObjectListView):
|
|||||||
'site', 'rack_group'
|
'site', 'rack_group'
|
||||||
).annotate(
|
).annotate(
|
||||||
powerfeed_count=Count('powerfeeds')
|
powerfeed_count=Count('powerfeeds')
|
||||||
)
|
).order_by(*PowerPanel._meta.ordering)
|
||||||
filterset = filters.PowerPanelFilterSet
|
filterset = filters.PowerPanelFilterSet
|
||||||
filterset_form = forms.PowerPanelFilterForm
|
filterset_form = forms.PowerPanelFilterForm
|
||||||
table = tables.PowerPanelTable
|
table = tables.PowerPanelTable
|
||||||
@ -2437,7 +2459,7 @@ class PowerPanelBulkDeleteView(BulkDeleteView):
|
|||||||
'site', 'rack_group'
|
'site', 'rack_group'
|
||||||
).annotate(
|
).annotate(
|
||||||
rack_count=Count('powerfeeds')
|
rack_count=Count('powerfeeds')
|
||||||
)
|
).order_by(*PowerPanel._meta.ordering)
|
||||||
filterset = filters.PowerPanelFilterSet
|
filterset = filters.PowerPanelFilterSet
|
||||||
table = tables.PowerPanelTable
|
table = tables.PowerPanelTable
|
||||||
|
|
||||||
|
28
netbox/extras/migrations/0046_update_jsonfield.py
Normal file
28
netbox/extras/migrations/0046_update_jsonfield.py
Normal file
@ -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),
|
||||||
|
),
|
||||||
|
]
|
@ -1,7 +1,6 @@
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.fields import JSONField
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
@ -104,7 +103,7 @@ class ObjectChange(models.Model):
|
|||||||
max_length=200,
|
max_length=200,
|
||||||
editable=False
|
editable=False
|
||||||
)
|
)
|
||||||
object_data = JSONField(
|
object_data = models.JSONField(
|
||||||
editable=False
|
editable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ from collections import OrderedDict
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.fields import JSONField
|
|
||||||
from django.core.validators import ValidationError
|
from django.core.validators import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
@ -499,7 +498,7 @@ class ConfigContext(ChangeLoggedModel):
|
|||||||
related_name='+',
|
related_name='+',
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
data = JSONField()
|
data = models.JSONField()
|
||||||
|
|
||||||
objects = ConfigContextQuerySet.as_manager()
|
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
|
A model which includes local configuration context data. This local data will override any inherited data from
|
||||||
ConfigContexts.
|
ConfigContexts.
|
||||||
"""
|
"""
|
||||||
local_context_data = JSONField(
|
local_context_data = models.JSONField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
@ -627,7 +626,7 @@ class JobResult(models.Model):
|
|||||||
choices=JobResultStatusChoices,
|
choices=JobResultStatusChoices,
|
||||||
default=JobResultStatusChoices.STATUS_PENDING
|
default=JobResultStatusChoices.STATUS_PENDING
|
||||||
)
|
)
|
||||||
data = JSONField(
|
data = models.JSONField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
@ -11,7 +11,7 @@ from django import forms
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils.decorators import classproperty
|
from django.utils.functional import classproperty
|
||||||
from django_rq import job
|
from django_rq import job
|
||||||
|
|
||||||
from extras.api.serializers import ScriptOutputSerializer
|
from extras.api.serializers import ScriptOutputSerializer
|
||||||
|
@ -24,7 +24,7 @@ class VRFViewSet(CustomFieldModelViewSet):
|
|||||||
queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate(
|
queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate(
|
||||||
ipaddress_count=get_subquery(IPAddress, 'vrf'),
|
ipaddress_count=get_subquery(IPAddress, 'vrf'),
|
||||||
prefix_count=get_subquery(Prefix, 'vrf')
|
prefix_count=get_subquery(Prefix, 'vrf')
|
||||||
)
|
).order_by(*VRF._meta.ordering)
|
||||||
serializer_class = serializers.VRFSerializer
|
serializer_class = serializers.VRFSerializer
|
||||||
filterset_class = filters.VRFFilterSet
|
filterset_class = filters.VRFFilterSet
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class VRFViewSet(CustomFieldModelViewSet):
|
|||||||
class RIRViewSet(ModelViewSet):
|
class RIRViewSet(ModelViewSet):
|
||||||
queryset = RIR.objects.annotate(
|
queryset = RIR.objects.annotate(
|
||||||
aggregate_count=Count('aggregates')
|
aggregate_count=Count('aggregates')
|
||||||
)
|
).order_by(*RIR._meta.ordering)
|
||||||
serializer_class = serializers.RIRSerializer
|
serializer_class = serializers.RIRSerializer
|
||||||
filterset_class = filters.RIRFilterSet
|
filterset_class = filters.RIRFilterSet
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class RoleViewSet(ModelViewSet):
|
|||||||
queryset = Role.objects.annotate(
|
queryset = Role.objects.annotate(
|
||||||
prefix_count=get_subquery(Prefix, 'role'),
|
prefix_count=get_subquery(Prefix, 'role'),
|
||||||
vlan_count=get_subquery(VLAN, 'role')
|
vlan_count=get_subquery(VLAN, 'role')
|
||||||
)
|
).order_by(*Role._meta.ordering)
|
||||||
serializer_class = serializers.RoleSerializer
|
serializer_class = serializers.RoleSerializer
|
||||||
filterset_class = filters.RoleFilterSet
|
filterset_class = filters.RoleFilterSet
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ class IPAddressViewSet(CustomFieldModelViewSet):
|
|||||||
class VLANGroupViewSet(ModelViewSet):
|
class VLANGroupViewSet(ModelViewSet):
|
||||||
queryset = VLANGroup.objects.prefetch_related('site').annotate(
|
queryset = VLANGroup.objects.prefetch_related('site').annotate(
|
||||||
vlan_count=Count('vlans')
|
vlan_count=Count('vlans')
|
||||||
)
|
).order_by(*VLANGroup._meta.ordering)
|
||||||
serializer_class = serializers.VLANGroupSerializer
|
serializer_class = serializers.VLANGroupSerializer
|
||||||
filterset_class = filters.VLANGroupFilterSet
|
filterset_class = filters.VLANGroupFilterSet
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ class VLANViewSet(CustomFieldModelViewSet):
|
|||||||
'site', 'group', 'tenant', 'role', 'tags'
|
'site', 'group', 'tenant', 'role', 'tags'
|
||||||
).annotate(
|
).annotate(
|
||||||
prefix_count=get_subquery(Prefix, 'vlan')
|
prefix_count=get_subquery(Prefix, 'vlan')
|
||||||
)
|
).order_by(*VLAN._meta.ordering)
|
||||||
serializer_class = serializers.VLANSerializer
|
serializer_class = serializers.VLANSerializer
|
||||||
filterset_class = filters.VLANFilterSet
|
filterset_class = filters.VLANFilterSet
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class VRFBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RIRListView(ObjectListView):
|
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 = filters.RIRFilterSet
|
||||||
filterset_form = forms.RIRFilterForm
|
filterset_form = forms.RIRFilterForm
|
||||||
table = tables.RIRDetailTable
|
table = tables.RIRDetailTable
|
||||||
@ -171,7 +171,7 @@ class RIRBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class RIRBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.RIRFilterSet
|
||||||
table = tables.RIRTable
|
table = tables.RIRTable
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ class RIRBulkDeleteView(BulkDeleteView):
|
|||||||
class AggregateListView(ObjectListView):
|
class AggregateListView(ObjectListView):
|
||||||
queryset = Aggregate.objects.prefetch_related('rir').annotate(
|
queryset = Aggregate.objects.prefetch_related('rir').annotate(
|
||||||
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
|
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
|
||||||
)
|
).order_by(*Aggregate._meta.ordering)
|
||||||
filterset = filters.AggregateFilterSet
|
filterset = filters.AggregateFilterSet
|
||||||
filterset_form = forms.AggregateFilterForm
|
filterset_form = forms.AggregateFilterForm
|
||||||
table = tables.AggregateDetailTable
|
table = tables.AggregateDetailTable
|
||||||
@ -650,7 +650,9 @@ class IPAddressBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class VLANGroupListView(ObjectListView):
|
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 = filters.VLANGroupFilterSet
|
||||||
filterset_form = forms.VLANGroupFilterForm
|
filterset_form = forms.VLANGroupFilterForm
|
||||||
table = tables.VLANGroupTable
|
table = tables.VLANGroupTable
|
||||||
@ -672,7 +674,9 @@ class VLANGroupBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class VLANGroupBulkDeleteView(BulkDeleteView):
|
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
|
filterset = filters.VLANGroupFilterSet
|
||||||
table = tables.VLANGroupTable
|
table = tables.VLANGroupTable
|
||||||
|
|
||||||
|
@ -46,7 +46,9 @@ SEARCH_MAX_RESULTS = 15
|
|||||||
SEARCH_TYPES = OrderedDict((
|
SEARCH_TYPES = OrderedDict((
|
||||||
# Circuits
|
# Circuits
|
||||||
('provider', {
|
('provider', {
|
||||||
'queryset': Provider.objects.annotate(count_circuits=Count('circuits')),
|
'queryset': Provider.objects.annotate(
|
||||||
|
count_circuits=Count('circuits')
|
||||||
|
).order_by(*Provider._meta.ordering),
|
||||||
'filterset': ProviderFilterSet,
|
'filterset': ProviderFilterSet,
|
||||||
'table': ProviderTable,
|
'table': ProviderTable,
|
||||||
'url': 'circuits:provider_list',
|
'url': 'circuits:provider_list',
|
||||||
@ -73,13 +75,17 @@ SEARCH_TYPES = OrderedDict((
|
|||||||
'url': 'dcim:rack_list',
|
'url': 'dcim:rack_list',
|
||||||
}),
|
}),
|
||||||
('rackgroup', {
|
('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,
|
'filterset': RackGroupFilterSet,
|
||||||
'table': RackGroupTable,
|
'table': RackGroupTable,
|
||||||
'url': 'dcim:rackgroup_list',
|
'url': 'dcim:rackgroup_list',
|
||||||
}),
|
}),
|
||||||
('devicetype', {
|
('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,
|
'filterset': DeviceTypeFilterSet,
|
||||||
'table': DeviceTypeTable,
|
'table': DeviceTypeTable,
|
||||||
'url': 'dcim:devicetype_list',
|
'url': 'dcim:devicetype_list',
|
||||||
@ -93,7 +99,9 @@ SEARCH_TYPES = OrderedDict((
|
|||||||
'url': 'dcim:device_list',
|
'url': 'dcim:device_list',
|
||||||
}),
|
}),
|
||||||
('virtualchassis', {
|
('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,
|
'filterset': VirtualChassisFilterSet,
|
||||||
'table': VirtualChassisTable,
|
'table': VirtualChassisTable,
|
||||||
'url': 'dcim:virtualchassis_list',
|
'url': 'dcim:virtualchassis_list',
|
||||||
|
@ -27,7 +27,7 @@ ERR_PRIVKEY_INVALID = "Invalid private key."
|
|||||||
class SecretRoleViewSet(ModelViewSet):
|
class SecretRoleViewSet(ModelViewSet):
|
||||||
queryset = SecretRole.objects.annotate(
|
queryset = SecretRole.objects.annotate(
|
||||||
secret_count=Count('secrets')
|
secret_count=Count('secrets')
|
||||||
)
|
).order_by(*SecretRole._meta.ordering)
|
||||||
serializer_class = serializers.SecretRoleSerializer
|
serializer_class = serializers.SecretRoleSerializer
|
||||||
filterset_class = filters.SecretRoleFilterSet
|
filterset_class = filters.SecretRoleFilterSet
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ def get_session_key(request):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SecretRoleListView(ObjectListView):
|
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
|
table = tables.SecretRoleTable
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ class SecretRoleBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class SecretRoleBulkDeleteView(BulkDeleteView):
|
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
|
table = tables.SecretRoleTable
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% for p in page.smart_pages %}
|
{% for p in page.smart_pages %}
|
||||||
{% if p %}
|
{% if p %}
|
||||||
<li{% ifequal page.number p %} class="active"{% endifequal %}><a href="{% querystring request page=p %}">{{ p }}</a></li>
|
<li{% if page.number == p %} class="active"{% endif %}><a href="{% querystring request page=p %}">{{ p }}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="disabled"><span>…</span></li>
|
<li class="disabled"><span>…</span></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -9,21 +9,21 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 col-md-2 col-md-offset-1">
|
<div class="col-sm-3 col-md-2 col-md-offset-1">
|
||||||
<ul class="nav nav-pills nav-stacked">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
<li{% ifequal active_tab "profile" %} class="active"{% endifequal %}>
|
<li{% if active_tab == "profile" %} class="active"{% endif %}>
|
||||||
<a href="{% url 'user:profile' %}">Profile</a>
|
<a href="{% url 'user:profile' %}">Profile</a>
|
||||||
</li>
|
</li>
|
||||||
<li{% ifequal active_tab "preferences" %} class="active"{% endifequal %}>
|
<li{% if active_tab == "preferences" %} class="active"{% endif %}>
|
||||||
<a href="{% url 'user:preferences' %}">Preferences</a>
|
<a href="{% url 'user:preferences' %}">Preferences</a>
|
||||||
</li>
|
</li>
|
||||||
{% if not request.user.ldap_username %}
|
{% if not request.user.ldap_username %}
|
||||||
<li{% ifequal active_tab "change_password" %} class="active"{% endifequal %}>
|
<li{% if active_tab == "change_password" %} class="active"{% endif %}>
|
||||||
<a href="{% url 'user:change_password' %}">Change Password</a>
|
<a href="{% url 'user:change_password' %}">Change Password</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li{% ifequal active_tab "api_tokens" %} class="active"{% endifequal %}>
|
<li{% if active_tab == "api_tokens" %} class="active"{% endif %}>
|
||||||
<a href="{% url 'user:token_list' %}">API Tokens</a>
|
<a href="{% url 'user:token_list' %}">API Tokens</a>
|
||||||
</li>
|
</li>
|
||||||
<li{% ifequal active_tab "userkey" %} class="active"{% endifequal %}>
|
<li{% if active_tab == "userkey" %} class="active"{% endif %}>
|
||||||
<a href="{% url 'user:userkey' %}">User Key</a>
|
<a href="{% url 'user:userkey' %}">User Key</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -15,8 +15,12 @@ from . import serializers
|
|||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupViewSet(ModelViewSet):
|
class TenantGroupViewSet(ModelViewSet):
|
||||||
queryset = TenantGroup.objects.annotate(
|
queryset = TenantGroup.objects.add_related_count(
|
||||||
tenant_count=get_subquery(Tenant, 'group')
|
TenantGroup.objects.all(),
|
||||||
|
Tenant,
|
||||||
|
'group',
|
||||||
|
'tenant_count',
|
||||||
|
cumulative=True
|
||||||
)
|
)
|
||||||
serializer_class = serializers.TenantGroupSerializer
|
serializer_class = serializers.TenantGroupSerializer
|
||||||
filterset_class = filters.TenantGroupFilterSet
|
filterset_class = filters.TenantGroupFilterSet
|
||||||
|
@ -43,7 +43,13 @@ class TenantGroupBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class TenantGroupBulkDeleteView(BulkDeleteView):
|
class TenantGroupBulkDeleteView(BulkDeleteView):
|
||||||
queryset = TenantGroup.objects.annotate(tenant_count=Count('tenants'))
|
queryset = TenantGroup.objects.add_related_count(
|
||||||
|
TenantGroup.objects.all(),
|
||||||
|
Tenant,
|
||||||
|
'group',
|
||||||
|
'tenant_count',
|
||||||
|
cumulative=True
|
||||||
|
)
|
||||||
table = tables.TenantGroupTable
|
table = tables.TenantGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
23
netbox/users/migrations/0010_update_jsonfield.py
Normal file
23
netbox/users/migrations/0010_update_jsonfield.py
Normal file
@ -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 = [
|
||||||
|
('users', '0009_replicate_permissions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='objectpermission',
|
||||||
|
name='constraints',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='userconfig',
|
||||||
|
name='data',
|
||||||
|
field=models.JSONField(default=dict),
|
||||||
|
),
|
||||||
|
]
|
@ -3,7 +3,7 @@ import os
|
|||||||
|
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
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.validators import MinLengthValidator
|
from django.core.validators import MinLengthValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
@ -56,7 +56,7 @@ class UserConfig(models.Model):
|
|||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name='config'
|
related_name='config'
|
||||||
)
|
)
|
||||||
data = JSONField(
|
data = models.JSONField(
|
||||||
default=dict
|
default=dict
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ class ObjectPermission(models.Model):
|
|||||||
base_field=models.CharField(max_length=30),
|
base_field=models.CharField(max_length=30),
|
||||||
help_text="The list of actions granted by this permission"
|
help_text="The list of actions granted by this permission"
|
||||||
)
|
)
|
||||||
constraints = JSONField(
|
constraints = models.JSONField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
help_text="Queryset filter matching the applicable objects of the selected type(s)"
|
help_text="Queryset filter matching the applicable objects of the selected type(s)"
|
||||||
|
@ -345,10 +345,9 @@ class ModelViewSet(_ModelViewSet):
|
|||||||
try:
|
try:
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
except ProtectedError as e:
|
except ProtectedError as e:
|
||||||
models = [
|
protected_objects = list(e.protected_objects)
|
||||||
'{} ({})'.format(o, o._meta) for o in e.protected_objects.all()
|
msg = f'Unable to delete object. {len(protected_objects)} dependent objects were found: '
|
||||||
]
|
msg += ', '.join([f'{obj} ({obj.pk})' for obj in protected_objects])
|
||||||
msg = 'Unable to delete object. The following dependent objects were found: {}'.format(', '.join(models))
|
|
||||||
logger.warning(msg)
|
logger.warning(msg)
|
||||||
return self.finalize_response(
|
return self.finalize_response(
|
||||||
request,
|
request,
|
||||||
|
@ -7,31 +7,17 @@ def handle_protectederror(obj, request, e):
|
|||||||
"""
|
"""
|
||||||
Generate a user-friendly error message in response to a ProtectedError exception.
|
Generate a user-friendly error message in response to a ProtectedError exception.
|
||||||
"""
|
"""
|
||||||
try:
|
protected_objects = list(e.protected_objects)
|
||||||
dep_class = e.protected_objects[0]._meta.verbose_name_plural
|
err_message = f"Unable to delete {obj._meta.verbose_name} <strong>{obj}</strong>. " \
|
||||||
except IndexError:
|
f"{len(protected_objects)} dependent objects were found: "
|
||||||
raise e
|
|
||||||
|
|
||||||
# Grammar for single versus multiple triggering objects
|
|
||||||
if type(obj) in (list, tuple):
|
|
||||||
err_message = "Unable to delete the requested {}. The following dependent {} were found: ".format(
|
|
||||||
obj[0]._meta.verbose_name_plural,
|
|
||||||
dep_class,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
err_message = "Unable to delete {} {}. The following dependent {} were found: ".format(
|
|
||||||
obj._meta.verbose_name,
|
|
||||||
obj,
|
|
||||||
dep_class,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Append dependent objects to error message
|
# Append dependent objects to error message
|
||||||
dependent_objects = []
|
dependent_objects = []
|
||||||
for obj in e.protected_objects:
|
for dependent in protected_objects:
|
||||||
if hasattr(obj, 'get_absolute_url'):
|
if hasattr(obj, 'get_absolute_url'):
|
||||||
dependent_objects.append('<a href="{}">{}</a>'.format(obj.get_absolute_url(), escape(obj)))
|
dependent_objects.append(f'<a href="{dependent.get_absolute_url()}">{escape(dependent)}</a>')
|
||||||
else:
|
else:
|
||||||
dependent_objects.append(str(obj))
|
dependent_objects.append(str(dependent))
|
||||||
err_message += ', '.join(dependent_objects)
|
err_message += ', '.join(dependent_objects)
|
||||||
|
|
||||||
messages.error(request, mark_safe(err_message))
|
messages.error(request, mark_safe(err_message))
|
||||||
|
@ -8,7 +8,7 @@ import yaml
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.postgres.forms import SimpleArrayField
|
from django.contrib.postgres.forms import SimpleArrayField
|
||||||
from django.contrib.postgres.forms.jsonb import JSONField as _JSONField, InvalidJSONInput
|
from django.forms.fields import JSONField as _JSONField, InvalidJSONInput
|
||||||
from django.core.exceptions import MultipleObjectsReturned
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.forms import BoundField
|
from django.forms import BoundField
|
||||||
|
@ -22,7 +22,7 @@ from . import serializers
|
|||||||
class ClusterTypeViewSet(ModelViewSet):
|
class ClusterTypeViewSet(ModelViewSet):
|
||||||
queryset = ClusterType.objects.annotate(
|
queryset = ClusterType.objects.annotate(
|
||||||
cluster_count=Count('clusters')
|
cluster_count=Count('clusters')
|
||||||
)
|
).order_by(*ClusterType._meta.ordering)
|
||||||
serializer_class = serializers.ClusterTypeSerializer
|
serializer_class = serializers.ClusterTypeSerializer
|
||||||
filterset_class = filters.ClusterTypeFilterSet
|
filterset_class = filters.ClusterTypeFilterSet
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class ClusterTypeViewSet(ModelViewSet):
|
|||||||
class ClusterGroupViewSet(ModelViewSet):
|
class ClusterGroupViewSet(ModelViewSet):
|
||||||
queryset = ClusterGroup.objects.annotate(
|
queryset = ClusterGroup.objects.annotate(
|
||||||
cluster_count=Count('clusters')
|
cluster_count=Count('clusters')
|
||||||
)
|
).order_by(*ClusterGroup._meta.ordering)
|
||||||
serializer_class = serializers.ClusterGroupSerializer
|
serializer_class = serializers.ClusterGroupSerializer
|
||||||
filterset_class = filters.ClusterGroupFilterSet
|
filterset_class = filters.ClusterGroupFilterSet
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class ClusterViewSet(CustomFieldModelViewSet):
|
|||||||
).annotate(
|
).annotate(
|
||||||
device_count=get_subquery(Device, 'cluster'),
|
device_count=get_subquery(Device, 'cluster'),
|
||||||
virtualmachine_count=get_subquery(VirtualMachine, 'cluster')
|
virtualmachine_count=get_subquery(VirtualMachine, 'cluster')
|
||||||
)
|
).order_by(*Cluster._meta.ordering)
|
||||||
serializer_class = serializers.ClusterSerializer
|
serializer_class = serializers.ClusterSerializer
|
||||||
filterset_class = filters.ClusterFilterSet
|
filterset_class = filters.ClusterFilterSet
|
||||||
|
|
||||||
|
18
netbox/virtualization/migrations/0017_update_jsonfield.py
Normal file
18
netbox/virtualization/migrations/0017_update_jsonfield.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.1b1 on 2020-07-16 16:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('virtualization', '0016_replicate_interfaces'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='virtualmachine',
|
||||||
|
name='local_context_data',
|
||||||
|
field=models.JSONField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -22,7 +22,7 @@ from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterf
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ClusterTypeListView(ObjectListView):
|
class ClusterTypeListView(ObjectListView):
|
||||||
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
|
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters')).order_by(*ClusterType._meta.ordering)
|
||||||
table = tables.ClusterTypeTable
|
table = tables.ClusterTypeTable
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class ClusterTypeBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class ClusterTypeBulkDeleteView(BulkDeleteView):
|
class ClusterTypeBulkDeleteView(BulkDeleteView):
|
||||||
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters'))
|
queryset = ClusterType.objects.annotate(cluster_count=Count('clusters')).order_by(*ClusterType._meta.ordering)
|
||||||
table = tables.ClusterTypeTable
|
table = tables.ClusterTypeTable
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class ClusterTypeBulkDeleteView(BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ClusterGroupListView(ObjectListView):
|
class ClusterGroupListView(ObjectListView):
|
||||||
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
|
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters')).order_by(*ClusterGroup._meta.ordering)
|
||||||
table = tables.ClusterGroupTable
|
table = tables.ClusterGroupTable
|
||||||
|
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class ClusterGroupBulkImportView(BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class ClusterGroupBulkDeleteView(BulkDeleteView):
|
class ClusterGroupBulkDeleteView(BulkDeleteView):
|
||||||
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters'))
|
queryset = ClusterGroup.objects.annotate(cluster_count=Count('clusters')).order_by(*ClusterGroup._meta.ordering)
|
||||||
table = tables.ClusterGroupTable
|
table = tables.ClusterGroupTable
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Django>=3.0,<3.1
|
Django==3.1rc1
|
||||||
django-cacheops==5.0.1
|
django-cacheops==5.0.1
|
||||||
django-cors-headers==3.4.0
|
django-cors-headers==3.4.0
|
||||||
django-debug-toolbar==2.2
|
django-debug-toolbar==2.2
|
||||||
|
Loading…
Reference in New Issue
Block a user