fixes #3428 - caching invalidation issues

Mitgate invalidation issues by using prefetch_related instead of select_related.
Also use invalidated_update instead of just update.
This commit is contained in:
John Anderson 2019-08-19 01:53:39 -04:00
parent dd4dafa7be
commit ade844f7a7
29 changed files with 236 additions and 294 deletions

View File

@ -43,7 +43,7 @@ class DeviceConnectionsReport(Report):
def test_console_connection(self):
# Check that every console port for every active device has a connection defined.
for console_port in ConsolePort.objects.select_related('device').filter(device__status=DEVICE_STATUS_ACTIVE):
for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=DEVICE_STATUS_ACTIVE):
if console_port.connected_endpoint is None:
self.log_failure(
console_port.device,

View File

@ -38,7 +38,7 @@ Add the name of the new field to `csv_headers` and included a CSV-friendly repre
### 4. Update relevant querysets
If you're adding a relational field (e.g. `ForeignKey`) and intend to include the data when retreiving a list of objects, be sure to include the field using `select_related()` or `prefetch_related()` as appropriate. This will optimize the view and avoid excessive database lookups.
If you're adding a relational field (e.g. `ForeignKey`) and intend to include the data when retreiving a list of objects, be sure to include the field using `prefetch_related()` as appropriate. This will optimize the view and avoid excessive database lookups.
### 5. Update API serializer

View File

@ -62,7 +62,7 @@ class CircuitTypeViewSet(ModelViewSet):
#
class CircuitViewSet(CustomFieldModelViewSet):
queryset = Circuit.objects.select_related('type', 'tenant', 'provider').prefetch_related('tags')
queryset = Circuit.objects.prefetch_related('type', 'tenant', 'provider').prefetch_related('tags')
serializer_class = serializers.CircuitSerializer
filterset_class = filters.CircuitFilter
@ -72,7 +72,7 @@ class CircuitViewSet(CustomFieldModelViewSet):
#
class CircuitTerminationViewSet(ModelViewSet):
queryset = CircuitTermination.objects.select_related(
queryset = CircuitTermination.objects.prefetch_related(
'circuit', 'site', 'connected_endpoint__device', 'cable'
)
serializer_class = serializers.CircuitTerminationSerializer

View File

@ -295,6 +295,6 @@ class CircuitTermination(CableTermination):
def get_peer_termination(self):
peer_side = 'Z' if self.term_side == 'A' else 'A'
try:
return CircuitTermination.objects.select_related('site').get(circuit=self.circuit, term_side=peer_side)
return CircuitTermination.objects.prefetch_related('site').get(circuit=self.circuit, term_side=peer_side)
except CircuitTermination.DoesNotExist:
return None

View File

@ -10,4 +10,4 @@ def update_circuit(instance, **kwargs):
"""
When a CircuitTermination has been modified, update the last_updated time of its parent Circuit.
"""
Circuit.objects.filter(pk=instance.circuit_id).update(last_updated=timezone.now())
Circuit.objects.filter(pk=instance.circuit_id).invalidated_update(last_updated=timezone.now())

View File

@ -35,11 +35,7 @@ class ProviderView(PermissionRequiredMixin, View):
def get(self, request, slug):
provider = get_object_or_404(Provider, slug=slug)
circuits = Circuit.objects.filter(provider=provider).select_related(
'type', 'tenant'
).prefetch_related(
'terminations__site'
)
circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
return render(request, 'circuits/provider.html', {
@ -134,10 +130,8 @@ class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class CircuitListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'circuits.view_circuit'
_terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
queryset = Circuit.objects.select_related(
'provider', 'type', 'tenant'
).prefetch_related(
'terminations__site'
queryset = Circuit.objects.prefetch_related(
'provider', 'type', 'tenant', 'terminations__site'
).annotate(
a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),
z_side=Subquery(_terminations.filter(term_side='Z').values('site__name')[:1]),
@ -153,13 +147,13 @@ class CircuitView(PermissionRequiredMixin, View):
def get(self, request, pk):
circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk)
termination_a = CircuitTermination.objects.select_related(
circuit = get_object_or_404(Circuit.objects.prefetch_related('provider', 'type', 'tenant__group'), pk=pk)
termination_a = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_A
).first()
termination_z = CircuitTermination.objects.select_related(
termination_z = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device'
).filter(
circuit=circuit, term_side=TERM_SIDE_Z
@ -199,7 +193,7 @@ class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'circuits.change_circuit'
queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
filter = filters.CircuitFilter
table = tables.CircuitTable
form = forms.CircuitBulkEditForm
@ -208,7 +202,7 @@ class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'circuits.delete_circuit'
queryset = Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
queryset = Circuit.objects.prefetch_related('provider', 'type', 'tenant').prefetch_related('terminations__site')
filter = filters.CircuitFilter
table = tables.CircuitTable
default_return_url = 'circuits:circuit_list'

View File

@ -109,10 +109,8 @@ class RegionViewSet(ModelViewSet):
#
class SiteViewSet(CustomFieldModelViewSet):
queryset = Site.objects.select_related(
'region', 'tenant'
).prefetch_related(
'tags'
queryset = Site.objects.prefetch_related(
'region', 'tenant', 'tags'
).annotate(
device_count=get_subquery(Device, 'site'),
rack_count=get_subquery(Rack, 'site'),
@ -140,7 +138,7 @@ class SiteViewSet(CustomFieldModelViewSet):
#
class RackGroupViewSet(ModelViewSet):
queryset = RackGroup.objects.select_related('site').annotate(
queryset = RackGroup.objects.prefetch_related('site').annotate(
rack_count=Count('racks')
)
serializer_class = serializers.RackGroupSerializer
@ -164,10 +162,8 @@ class RackRoleViewSet(ModelViewSet):
#
class RackViewSet(CustomFieldModelViewSet):
queryset = Rack.objects.select_related(
'site', 'group__site', 'role', 'tenant'
).prefetch_related(
'tags'
queryset = Rack.objects.prefetch_related(
'site', 'group__site', 'role', 'tenant', 'tags'
).annotate(
device_count=get_subquery(Device, 'rack'),
powerfeed_count=get_subquery(PowerFeed, 'rack')
@ -206,7 +202,7 @@ class RackViewSet(CustomFieldModelViewSet):
#
class RackReservationViewSet(ModelViewSet):
queryset = RackReservation.objects.select_related('rack', 'user', 'tenant')
queryset = RackReservation.objects.prefetch_related('rack', 'user', 'tenant')
serializer_class = serializers.RackReservationSerializer
filterset_class = filters.RackReservationFilter
@ -234,7 +230,7 @@ class ManufacturerViewSet(ModelViewSet):
#
class DeviceTypeViewSet(CustomFieldModelViewSet):
queryset = DeviceType.objects.select_related('manufacturer').prefetch_related('tags').annotate(
queryset = DeviceType.objects.prefetch_related('manufacturer').prefetch_related('tags').annotate(
device_count=Count('instances')
)
serializer_class = serializers.DeviceTypeSerializer
@ -246,49 +242,49 @@ class DeviceTypeViewSet(CustomFieldModelViewSet):
#
class ConsolePortTemplateViewSet(ModelViewSet):
queryset = ConsolePortTemplate.objects.select_related('device_type__manufacturer')
queryset = ConsolePortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsolePortTemplateSerializer
filterset_class = filters.ConsolePortTemplateFilter
class ConsoleServerPortTemplateViewSet(ModelViewSet):
queryset = ConsoleServerPortTemplate.objects.select_related('device_type__manufacturer')
queryset = ConsoleServerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsoleServerPortTemplateSerializer
filterset_class = filters.ConsoleServerPortTemplateFilter
class PowerPortTemplateViewSet(ModelViewSet):
queryset = PowerPortTemplate.objects.select_related('device_type__manufacturer')
queryset = PowerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerPortTemplateSerializer
filterset_class = filters.PowerPortTemplateFilter
class PowerOutletTemplateViewSet(ModelViewSet):
queryset = PowerOutletTemplate.objects.select_related('device_type__manufacturer')
queryset = PowerOutletTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerOutletTemplateSerializer
filterset_class = filters.PowerOutletTemplateFilter
class InterfaceTemplateViewSet(ModelViewSet):
queryset = InterfaceTemplate.objects.select_related('device_type__manufacturer')
queryset = InterfaceTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.InterfaceTemplateSerializer
filterset_class = filters.InterfaceTemplateFilter
class FrontPortTemplateViewSet(ModelViewSet):
queryset = FrontPortTemplate.objects.select_related('device_type__manufacturer')
queryset = FrontPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.FrontPortTemplateSerializer
filterset_class = filters.FrontPortTemplateFilter
class RearPortTemplateViewSet(ModelViewSet):
queryset = RearPortTemplate.objects.select_related('device_type__manufacturer')
queryset = RearPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.RearPortTemplateSerializer
filterset_class = filters.RearPortTemplateFilter
class DeviceBayTemplateViewSet(ModelViewSet):
queryset = DeviceBayTemplate.objects.select_related('device_type__manufacturer')
queryset = DeviceBayTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.DeviceBayTemplateSerializer
filterset_class = filters.DeviceBayTemplateFilter
@ -324,11 +320,9 @@ class PlatformViewSet(ModelViewSet):
#
class DeviceViewSet(CustomFieldModelViewSet):
queryset = Device.objects.select_related(
queryset = Device.objects.prefetch_related(
'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'rack', 'parent_bay',
'virtual_chassis__master',
).prefetch_related(
'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags',
'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags',
)
filterset_class = filters.DeviceFilter
@ -429,52 +423,36 @@ class DeviceViewSet(CustomFieldModelViewSet):
#
class ConsolePortViewSet(CableTraceMixin, ModelViewSet):
queryset = ConsolePort.objects.select_related(
'device', 'connected_endpoint__device', 'cable'
).prefetch_related(
'tags'
)
queryset = ConsolePort.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.ConsolePortSerializer
filterset_class = filters.ConsolePortFilter
class ConsoleServerPortViewSet(CableTraceMixin, ModelViewSet):
queryset = ConsoleServerPort.objects.select_related(
'device', 'connected_endpoint__device', 'cable'
).prefetch_related(
'tags'
)
queryset = ConsoleServerPort.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.ConsoleServerPortSerializer
filterset_class = filters.ConsoleServerPortFilter
class PowerPortViewSet(CableTraceMixin, ModelViewSet):
queryset = PowerPort.objects.select_related(
'device', '_connected_poweroutlet__device', '_connected_powerfeed', 'cable'
).prefetch_related(
'tags'
queryset = PowerPort.objects.prefetch_related(
'device', '_connected_poweroutlet__device', '_connected_powerfeed', 'cable', 'tags'
)
serializer_class = serializers.PowerPortSerializer
filterset_class = filters.PowerPortFilter
class PowerOutletViewSet(CableTraceMixin, ModelViewSet):
queryset = PowerOutlet.objects.select_related(
'device', 'connected_endpoint__device', 'cable'
).prefetch_related(
'tags'
)
queryset = PowerOutlet.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.PowerOutletSerializer
filterset_class = filters.PowerOutletFilter
class InterfaceViewSet(CableTraceMixin, ModelViewSet):
queryset = Interface.objects.filter(
queryset = Interface.objects.prefetch_related(
'device', '_connected_interface', '_connected_circuittermination', 'cable', 'ip_addresses', 'tags'
).filter(
device__isnull=False
).select_related(
'device', '_connected_interface', '_connected_circuittermination', 'cable'
).prefetch_related(
'ip_addresses', 'tags'
)
serializer_class = serializers.InterfaceSerializer
filterset_class = filters.InterfaceFilter
@ -491,33 +469,25 @@ class InterfaceViewSet(CableTraceMixin, ModelViewSet):
class FrontPortViewSet(ModelViewSet):
queryset = FrontPort.objects.select_related(
'device__device_type__manufacturer', 'rear_port', 'cable'
).prefetch_related(
'tags'
)
queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags')
serializer_class = serializers.FrontPortSerializer
filterset_class = filters.FrontPortFilter
class RearPortViewSet(ModelViewSet):
queryset = RearPort.objects.select_related(
'device__device_type__manufacturer', 'cable'
).prefetch_related(
'tags'
)
queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags')
serializer_class = serializers.RearPortSerializer
filterset_class = filters.RearPortFilter
class DeviceBayViewSet(ModelViewSet):
queryset = DeviceBay.objects.select_related('installed_device').prefetch_related('tags')
queryset = DeviceBay.objects.prefetch_related('installed_device').prefetch_related('tags')
serializer_class = serializers.DeviceBaySerializer
filterset_class = filters.DeviceBayFilter
class InventoryItemViewSet(ModelViewSet):
queryset = InventoryItem.objects.select_related('device', 'manufacturer').prefetch_related('tags')
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer').prefetch_related('tags')
serializer_class = serializers.InventoryItemSerializer
filterset_class = filters.InventoryItemFilter
@ -527,7 +497,7 @@ class InventoryItemViewSet(ModelViewSet):
#
class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = ConsolePort.objects.select_related(
queryset = ConsolePort.objects.prefetch_related(
'device', 'connected_endpoint__device'
).filter(
connected_endpoint__isnull=False
@ -537,7 +507,7 @@ class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet):
class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = PowerPort.objects.select_related(
queryset = PowerPort.objects.prefetch_related(
'device', 'connected_endpoint__device'
).filter(
_connected_poweroutlet__isnull=False
@ -547,7 +517,7 @@ class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = Interface.objects.select_related(
queryset = Interface.objects.prefetch_related(
'device', '_connected_interface__device'
).filter(
# Avoid duplicate connections by only selecting the lower PK in a connected pair
@ -587,7 +557,7 @@ class VirtualChassisViewSet(ModelViewSet):
#
class PowerPanelViewSet(ModelViewSet):
queryset = PowerPanel.objects.select_related(
queryset = PowerPanel.objects.prefetch_related(
'site', 'rack_group'
).annotate(
powerfeed_count=Count('powerfeeds')
@ -601,11 +571,7 @@ class PowerPanelViewSet(ModelViewSet):
#
class PowerFeedViewSet(CustomFieldModelViewSet):
queryset = PowerFeed.objects.select_related(
'power_panel', 'rack'
).prefetch_related(
'tags'
)
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack', 'tags')
serializer_class = serializers.PowerFeedSerializer
filterset_class = filters.PowerFeedFilter

View File

@ -632,7 +632,7 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
)
group_id = ChainedModelChoiceField(
label='Rack group',
queryset=RackGroup.objects.select_related('site'),
queryset=RackGroup.objects.prefetch_related('site'),
chains=(
('site', 'site'),
),
@ -745,7 +745,7 @@ class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm):
)
)
group_id = FilterChoiceField(
queryset=RackGroup.objects.select_related('site'),
queryset=RackGroup.objects.prefetch_related('site'),
label='Rack group',
null_label='-- None --',
widget=APISelectMultiple(
@ -1391,14 +1391,14 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm):
interface_ids = self.instance.vc_interfaces.values('pk')
# Collect interface IPs
interface_ips = IPAddress.objects.select_related('interface').filter(
interface_ips = IPAddress.objects.prefetch_related('interface').filter(
family=family, interface_id__in=interface_ids
)
if interface_ips:
ip_list = [(ip.id, '{} ({})'.format(ip.address, ip.interface)) for ip in interface_ips]
ip_choices.append(('Interface IPs', ip_list))
# Collect NAT IPs
nat_ips = IPAddress.objects.select_related('nat_inside').filter(
nat_ips = IPAddress.objects.prefetch_related('nat_inside').filter(
family=family, nat_inside__interface__in=interface_ids
)
if nat_ips:
@ -1710,7 +1710,7 @@ class DeviceFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
)
)
rack_group_id = FilterChoiceField(
queryset=RackGroup.objects.select_related(
queryset=RackGroup.objects.prefetch_related(
'site'
),
label='Rack group',
@ -1749,7 +1749,7 @@ class DeviceFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
)
)
device_type_id = FilterChoiceField(
queryset=DeviceType.objects.select_related(
queryset=DeviceType.objects.prefetch_related(
'manufacturer'
),
label='Model',

View File

@ -607,7 +607,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
# Update racked devices if the assigned Site has been changed.
if _site_id is not None and self.site_id != _site_id:
Device.objects.filter(rack=self).update(site_id=self.site.pk)
Device.objects.filter(rack=self).invalidated_update(site_id=self.site.pk)
def to_csv(self):
return (
@ -664,7 +664,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
# Add devices to rack units list
if self.pk:
for device in Device.objects.select_related('device_type__manufacturer', 'device_role')\
for device in Device.objects.prefetch_related('device_type__manufacturer', 'device_role')\
.annotate(devicebay_count=Count('device_bays'))\
.exclude(pk=exclude)\
.filter(rack=self, position__gt=0)\
@ -697,7 +697,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
"""
# Gather all devices which consume U space within the rack
devices = self.devices.select_related('device_type').filter(position__gte=1).exclude(pk__in=exclude)
devices = self.devices.prefetch_related('device_type').filter(position__gte=1).exclude(pk__in=exclude)
# Initialize the rack unit skeleton
units = list(range(1, self.u_height + 1))
@ -1738,7 +1738,7 @@ class Device(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
)
# Update Site and Rack assignment for any child Devices
Device.objects.filter(parent_bay__device=self).update(site=self.site, rack=self.rack)
Device.objects.filter(parent_bay__device=self).invalidated_update(site=self.site, rack=self.rack)
def to_csv(self):
return (

View File

@ -10,7 +10,7 @@ def assign_virtualchassis_master(instance, created, **kwargs):
When a VirtualChassis is created, automatically assign its master device to the VC.
"""
if created:
Device.objects.filter(pk=instance.master.pk).update(virtual_chassis=instance, vc_position=None)
Device.objects.filter(pk=instance.master.pk).invalidated_update(virtual_chassis=instance, vc_position=None)
@receiver(pre_delete, sender=VirtualChassis)
@ -18,7 +18,7 @@ def clear_virtualchassis_members(instance, **kwargs):
"""
When a VirtualChassis is deleted, nullify the vc_position and vc_priority fields of its prior members.
"""
Device.objects.filter(virtual_chassis=instance.pk).update(vc_position=None, vc_priority=None)
Device.objects.filter(virtual_chassis=instance.pk).invalidated_update(vc_position=None, vc_priority=None)
@receiver(post_save, sender=Cable)

View File

@ -3430,11 +3430,11 @@ class VirtualChassisTest(APITestCase):
# Create two VirtualChassis with three members each
self.vc1 = VirtualChassis.objects.create(master=self.device1, domain='test-domain-1')
Device.objects.filter(pk=self.device2.pk).update(virtual_chassis=self.vc1, vc_position=2)
Device.objects.filter(pk=self.device3.pk).update(virtual_chassis=self.vc1, vc_position=3)
Device.objects.filter(pk=self.device2.pk).invalidated_update(virtual_chassis=self.vc1, vc_position=2)
Device.objects.filter(pk=self.device3.pk).invalidated_update(virtual_chassis=self.vc1, vc_position=3)
self.vc2 = VirtualChassis.objects.create(master=self.device4, domain='test-domain-2')
Device.objects.filter(pk=self.device5.pk).update(virtual_chassis=self.vc2, vc_position=2)
Device.objects.filter(pk=self.device6.pk).update(virtual_chassis=self.vc2, vc_position=3)
Device.objects.filter(pk=self.device5.pk).invalidated_update(virtual_chassis=self.vc2, vc_position=2)
Device.objects.filter(pk=self.device6.pk).invalidated_update(virtual_chassis=self.vc2, vc_position=3)
def test_get_virtualchassis(self):

View File

@ -442,11 +442,11 @@ class VirtualChassisTestCase(TestCase):
# Create three VirtualChassis with two members each
vc1 = VirtualChassis.objects.create(master=device1, domain='test-domain-1')
Device.objects.filter(pk=device2.pk).update(virtual_chassis=vc1, vc_position=2)
Device.objects.filter(pk=device2.pk).invalidated_update(virtual_chassis=vc1, vc_position=2)
vc2 = VirtualChassis.objects.create(master=device3, domain='test-domain-2')
Device.objects.filter(pk=device4.pk).update(virtual_chassis=vc2, vc_position=2)
Device.objects.filter(pk=device4.pk).invalidated_update(virtual_chassis=vc2, vc_position=2)
vc3 = VirtualChassis.objects.create(master=device5, domain='test-domain-3')
Device.objects.filter(pk=device6.pk).update(virtual_chassis=vc3, vc_position=2)
Device.objects.filter(pk=device6.pk).invalidated_update(virtual_chassis=vc3, vc_position=2)
def test_virtualchassis_list(self):

View File

@ -185,7 +185,7 @@ class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class SiteListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_site'
queryset = Site.objects.select_related('region', 'tenant')
queryset = Site.objects.prefetch_related('region', 'tenant')
filter = filters.SiteFilter
filter_form = forms.SiteFilterForm
table = tables.SiteTable
@ -197,7 +197,7 @@ class SiteView(PermissionRequiredMixin, View):
def get(self, request, slug):
site = get_object_or_404(Site.objects.select_related('region', 'tenant__group'), slug=slug)
site = get_object_or_404(Site.objects.prefetch_related('region', 'tenant__group'), slug=slug)
stats = {
'rack_count': Rack.objects.filter(site=site).count(),
'device_count': Device.objects.filter(site=site).count(),
@ -246,7 +246,7 @@ class SiteBulkImportView(PermissionRequiredMixin, BulkImportView):
class SiteBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_site'
queryset = Site.objects.select_related('region', 'tenant')
queryset = Site.objects.prefetch_related('region', 'tenant')
filter = filters.SiteFilter
table = tables.SiteTable
form = forms.SiteBulkEditForm
@ -255,7 +255,7 @@ class SiteBulkEditView(PermissionRequiredMixin, BulkEditView):
class SiteBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_site'
queryset = Site.objects.select_related('region', 'tenant')
queryset = Site.objects.prefetch_related('region', 'tenant')
filter = filters.SiteFilter
table = tables.SiteTable
default_return_url = 'dcim:site_list'
@ -267,7 +267,7 @@ class SiteBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class RackGroupListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_rackgroup'
queryset = RackGroup.objects.select_related('site').annotate(rack_count=Count('racks'))
queryset = RackGroup.objects.prefetch_related('site').annotate(rack_count=Count('racks'))
filter = filters.RackGroupFilter
filter_form = forms.RackGroupFilterForm
table = tables.RackGroupTable
@ -294,7 +294,7 @@ class RackGroupBulkImportView(PermissionRequiredMixin, BulkImportView):
class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_rackgroup'
queryset = RackGroup.objects.select_related('site').annotate(rack_count=Count('racks'))
queryset = RackGroup.objects.prefetch_related('site').annotate(rack_count=Count('racks'))
filter = filters.RackGroupFilter
table = tables.RackGroupTable
default_return_url = 'dcim:rackgroup_list'
@ -342,10 +342,8 @@ class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class RackListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_rack'
queryset = Rack.objects.select_related(
'site', 'group', 'tenant', 'role'
).prefetch_related(
'devices__device_type'
queryset = Rack.objects.prefetch_related(
'site', 'group', 'tenant', 'role', 'devices__device_type'
).annotate(
device_count=Count('devices')
)
@ -363,11 +361,7 @@ class RackElevationListView(PermissionRequiredMixin, View):
def get(self, request):
racks = Rack.objects.select_related(
'site', 'group', 'tenant', 'role'
).prefetch_related(
'devices__device_type'
)
racks = Rack.objects.prefetch_related('site', 'group', 'tenant', 'role', 'devices__device_type')
racks = filters.RackFilter(request.GET, racks).qs
total_count = racks.count()
@ -402,15 +396,18 @@ class RackView(PermissionRequiredMixin, View):
def get(self, request, pk):
rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
rack = get_object_or_404(Rack.objects.prefetch_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True) \
.select_related('device_type__manufacturer')
nonracked_devices = Device.objects.filter(
rack=rack,
position__isnull=True,
parent_bay__isnull=True
).prefetch_related('device_type__manufacturer')
next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name').first()
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
reservations = RackReservation.objects.filter(rack=rack)
power_feeds = PowerFeed.objects.filter(rack=rack).select_related('power_panel')
power_feeds = PowerFeed.objects.filter(rack=rack).prefetch_related('power_panel')
return render(request, 'dcim/rack.html', {
'rack': rack,
@ -451,7 +448,7 @@ class RackBulkImportView(PermissionRequiredMixin, BulkImportView):
class RackBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_rack'
queryset = Rack.objects.select_related('site', 'group', 'tenant', 'role')
queryset = Rack.objects.prefetch_related('site', 'group', 'tenant', 'role')
filter = filters.RackFilter
table = tables.RackTable
form = forms.RackBulkEditForm
@ -460,7 +457,7 @@ class RackBulkEditView(PermissionRequiredMixin, BulkEditView):
class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_rack'
queryset = Rack.objects.select_related('site', 'group', 'tenant', 'role')
queryset = Rack.objects.prefetch_related('site', 'group', 'tenant', 'role')
filter = filters.RackFilter
table = tables.RackTable
default_return_url = 'dcim:rack_list'
@ -472,7 +469,7 @@ class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class RackReservationListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_rackreservation'
queryset = RackReservation.objects.select_related('rack__site')
queryset = RackReservation.objects.prefetch_related('rack__site')
filter = filters.RackReservationFilter
filter_form = forms.RackReservationFilterForm
table = tables.RackReservationTable
@ -508,7 +505,7 @@ class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
class RackReservationBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_rackreservation'
queryset = RackReservation.objects.select_related('rack', 'user')
queryset = RackReservation.objects.prefetch_related('rack', 'user')
filter = filters.RackReservationFilter
table = tables.RackReservationTable
form = forms.RackReservationBulkEditForm
@ -517,7 +514,7 @@ class RackReservationBulkEditView(PermissionRequiredMixin, BulkEditView):
class RackReservationBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_rackreservation'
queryset = RackReservation.objects.select_related('rack', 'user')
queryset = RackReservation.objects.prefetch_related('rack', 'user')
filter = filters.RackReservationFilter
table = tables.RackReservationTable
default_return_url = 'dcim:rackreservation_list'
@ -569,7 +566,7 @@ class ManufacturerBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class DeviceTypeListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_devicetype'
queryset = DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances'))
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances'))
filter = filters.DeviceTypeFilter
filter_form = forms.DeviceTypeFilterForm
table = tables.DeviceTypeTable
@ -666,7 +663,7 @@ class DeviceTypeBulkImportView(PermissionRequiredMixin, BulkImportView):
class DeviceTypeBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_devicetype'
queryset = DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances'))
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances'))
filter = filters.DeviceTypeFilter
table = tables.DeviceTypeTable
form = forms.DeviceTypeBulkEditForm
@ -675,7 +672,7 @@ class DeviceTypeBulkEditView(PermissionRequiredMixin, BulkEditView):
class DeviceTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_devicetype'
queryset = DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances'))
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances'))
filter = filters.DeviceTypeFilter
table = tables.DeviceTypeTable
default_return_url = 'dcim:devicetype_list'
@ -907,7 +904,7 @@ class PlatformBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class DeviceListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_device'
queryset = Device.objects.select_related(
queryset = Device.objects.prefetch_related(
'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6'
)
filter = filters.DeviceFilter
@ -921,7 +918,7 @@ class DeviceView(PermissionRequiredMixin, View):
def get(self, request, pk):
device = get_object_or_404(Device.objects.select_related(
device = get_object_or_404(Device.objects.prefetch_related(
'site__region', 'rack__group', 'tenant__group', 'device_role', 'platform'
), pk=pk)
@ -934,32 +931,31 @@ class DeviceView(PermissionRequiredMixin, View):
vc_members = []
# Console ports
console_ports = device.consoleports.select_related('connected_endpoint__device', 'cable')
console_ports = device.consoleports.prefetch_related('connected_endpoint__device', 'cable')
# Console server ports
consoleserverports = device.consoleserverports.select_related('connected_endpoint__device', 'cable')
consoleserverports = device.consoleserverports.prefetch_related('connected_endpoint__device', 'cable')
# Power ports
power_ports = device.powerports.select_related('_connected_poweroutlet__device', 'cable')
power_ports = device.powerports.prefetch_related('_connected_poweroutlet__device', 'cable')
# Power outlets
poweroutlets = device.poweroutlets.select_related('connected_endpoint__device', 'cable', 'power_port')
poweroutlets = device.poweroutlets.prefetch_related('connected_endpoint__device', 'cable', 'power_port')
# Interfaces
interfaces = device.vc_interfaces.select_related(
'lag', '_connected_interface__device', '_connected_circuittermination__circuit', 'cable'
).prefetch_related(
interfaces = device.vc_interfaces.prefetch_related(
'lag', '_connected_interface__device', '_connected_circuittermination__circuit', 'cable',
'cable__termination_a', 'cable__termination_b', 'ip_addresses', 'tags'
)
# Front ports
front_ports = device.frontports.select_related('rear_port', 'cable')
front_ports = device.frontports.prefetch_related('rear_port', 'cable')
# Rear ports
rear_ports = device.rearports.select_related('cable')
rear_ports = device.rearports.prefetch_related('cable')
# Device bays
device_bays = device.device_bays.select_related('installed_device__device_type__manufacturer')
device_bays = device.device_bays.prefetch_related('installed_device__device_type__manufacturer')
# Services
services = device.services.all()
@ -972,7 +968,7 @@ class DeviceView(PermissionRequiredMixin, View):
site=device.site, device_role=device.device_role
).exclude(
pk=device.pk
).select_related(
).prefetch_related(
'rack', 'device_type__manufacturer'
)[:10]
@ -1005,10 +1001,8 @@ class DeviceInventoryView(PermissionRequiredMixin, View):
device = get_object_or_404(Device, pk=pk)
inventory_items = InventoryItem.objects.filter(
device=device, parent=None
).select_related(
'manufacturer'
).prefetch_related(
'child_items'
'manufacturer', 'child_items'
)
return render(request, 'dcim/device_inventory.html', {
@ -1037,7 +1031,7 @@ class DeviceLLDPNeighborsView(PermissionRequiredMixin, View):
def get(self, request, pk):
device = get_object_or_404(Device, pk=pk)
interfaces = device.vc_interfaces.connectable().select_related(
interfaces = device.vc_interfaces.connectable().prefetch_related(
'_connected_interface__device'
)
@ -1114,7 +1108,7 @@ class ChildDeviceBulkImportView(PermissionRequiredMixin, BulkImportView):
class DeviceBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_device'
queryset = Device.objects.select_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
filter = filters.DeviceFilter
table = tables.DeviceTable
form = forms.DeviceBulkEditForm
@ -1123,7 +1117,7 @@ class DeviceBulkEditView(PermissionRequiredMixin, BulkEditView):
class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_device'
queryset = Device.objects.select_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
filter = filters.DeviceFilter
table = tables.DeviceTable
default_return_url = 'dcim:device_list'
@ -1310,7 +1304,7 @@ class InterfaceView(PermissionRequiredMixin, View):
# Get assigned IP addresses
ipaddress_table = InterfaceIPAddressTable(
data=interface.ip_addresses.select_related('vrf', 'tenant'),
data=interface.ip_addresses.prefetch_related('vrf', 'tenant'),
orderable=False
)
@ -1319,7 +1313,7 @@ class InterfaceView(PermissionRequiredMixin, View):
if interface.untagged_vlan is not None:
vlans.append(interface.untagged_vlan)
vlans[0].tagged = False
for vlan in interface.tagged_vlans.select_related('site', 'group', 'tenant', 'role'):
for vlan in interface.tagged_vlans.prefetch_related('site', 'group', 'tenant', 'role'):
vlan.tagged = True
vlans.append(vlan)
vlan_table = InterfaceVLANTable(
@ -1842,7 +1836,7 @@ class CableBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class ConsoleConnectionsListView(PermissionRequiredMixin, ObjectListView):
permission_required = ('dcim.view_consoleport', 'dcim.view_consoleserverport')
queryset = ConsolePort.objects.select_related(
queryset = ConsolePort.objects.prefetch_related(
'device', 'connected_endpoint__device'
).filter(
connected_endpoint__isnull=False
@ -1873,7 +1867,7 @@ class ConsoleConnectionsListView(PermissionRequiredMixin, ObjectListView):
class PowerConnectionsListView(PermissionRequiredMixin, ObjectListView):
permission_required = ('dcim.view_powerport', 'dcim.view_poweroutlet')
queryset = PowerPort.objects.select_related(
queryset = PowerPort.objects.prefetch_related(
'device', '_connected_poweroutlet__device'
).filter(
_connected_poweroutlet__isnull=False
@ -1904,7 +1898,7 @@ class PowerConnectionsListView(PermissionRequiredMixin, ObjectListView):
class InterfaceConnectionsListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_interface'
queryset = Interface.objects.select_related(
queryset = Interface.objects.prefetch_related(
'device', 'cable', '_connected_interface__device'
).filter(
# Avoid duplicate connections by only selecting the lower PK in a connected pair
@ -1947,7 +1941,7 @@ class InterfaceConnectionsListView(PermissionRequiredMixin, ObjectListView):
class InventoryItemListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_inventoryitem'
queryset = InventoryItem.objects.select_related('device', 'manufacturer')
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
filter = filters.InventoryItemFilter
filter_form = forms.InventoryItemFilterForm
table = tables.InventoryItemTable
@ -1982,7 +1976,7 @@ class InventoryItemBulkImportView(PermissionRequiredMixin, BulkImportView):
class InventoryItemBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_inventoryitem'
queryset = InventoryItem.objects.select_related('device', 'manufacturer')
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
filter = filters.InventoryItemFilter
table = tables.InventoryItemTable
form = forms.InventoryItemBulkEditForm
@ -1991,7 +1985,7 @@ class InventoryItemBulkEditView(PermissionRequiredMixin, BulkEditView):
class InventoryItemBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_inventoryitem'
queryset = InventoryItem.objects.select_related('device', 'manufacturer')
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
table = tables.InventoryItemTable
template_name = 'dcim/inventoryitem_bulk_delete.html'
default_return_url = 'dcim:inventoryitem_list'
@ -2003,7 +1997,7 @@ class InventoryItemBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class VirtualChassisListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_virtualchassis'
queryset = VirtualChassis.objects.select_related('master').annotate(member_count=Count('members'))
queryset = VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members'))
table = tables.VirtualChassisTable
filter = filters.VirtualChassisFilter
filter_form = forms.VirtualChassisFilterForm
@ -2023,7 +2017,7 @@ class VirtualChassisCreateView(PermissionRequiredMixin, View):
return redirect('dcim:device_list')
device_queryset = Device.objects.filter(
pk__in=pk_form.cleaned_data.get('pk')
).select_related('rack').order_by('vc_position')
).prefetch_related('rack').order_by('vc_position')
VCMemberFormSet = modelformset_factory(
model=Device,
@ -2077,7 +2071,7 @@ class VirtualChassisEditView(PermissionRequiredMixin, GetReturnURLMixin, View):
formset=forms.BaseVCMemberFormSet,
extra=0
)
members_queryset = virtual_chassis.members.select_related('rack').order_by('vc_position')
members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
vc_form = forms.VirtualChassisForm(instance=virtual_chassis)
vc_form.fields['master'].queryset = members_queryset
@ -2098,7 +2092,7 @@ class VirtualChassisEditView(PermissionRequiredMixin, GetReturnURLMixin, View):
formset=forms.BaseVCMemberFormSet,
extra=0
)
members_queryset = virtual_chassis.members.select_related('rack').order_by('vc_position')
members_queryset = virtual_chassis.members.prefetch_related('rack').order_by('vc_position')
vc_form = forms.VirtualChassisForm(request.POST, instance=virtual_chassis)
vc_form.fields['master'].queryset = members_queryset
@ -2114,7 +2108,7 @@ class VirtualChassisEditView(PermissionRequiredMixin, GetReturnURLMixin, View):
# Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
# duplicate positions. Then save each member instance.
members = formset.save(commit=False)
Device.objects.filter(pk__in=[m.pk for m in members]).update(vc_position=None)
Device.objects.filter(pk__in=[m.pk for m in members]).invalidated_update(vc_position=None)
for member in members:
member.save()
@ -2215,12 +2209,13 @@ class VirtualChassisRemoveMemberView(PermissionRequiredMixin, GetReturnURLMixin,
if form.is_valid():
Device.objects.filter(pk=device.pk).update(
Device.objects.filter(pk=device.pk).invalidated_update(
virtual_chassis=None,
vc_position=None,
vc_priority=None
)
msg = 'Removed {} from virtual chassis {}'.format(device, device.virtual_chassis)
messages.success(request, msg)
@ -2239,7 +2234,7 @@ class VirtualChassisRemoveMemberView(PermissionRequiredMixin, GetReturnURLMixin,
class PowerPanelListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_powerpanel'
queryset = PowerPanel.objects.select_related(
queryset = PowerPanel.objects.prefetch_related(
'site', 'rack_group'
).annotate(
powerfeed_count=Count('powerfeeds')
@ -2255,9 +2250,9 @@ class PowerPanelView(PermissionRequiredMixin, View):
def get(self, request, pk):
powerpanel = get_object_or_404(PowerPanel.objects.select_related('site', 'rack_group'), pk=pk)
powerpanel = get_object_or_404(PowerPanel.objects.prefetch_related('site', 'rack_group'), pk=pk)
powerfeed_table = tables.PowerFeedTable(
data=PowerFeed.objects.filter(power_panel=powerpanel).select_related('rack'),
data=PowerFeed.objects.filter(power_panel=powerpanel).prefetch_related('rack'),
orderable=False
)
powerfeed_table.exclude = ['power_panel']
@ -2294,7 +2289,7 @@ class PowerPanelBulkImportView(PermissionRequiredMixin, BulkImportView):
class PowerPanelBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_powerpanel'
queryset = PowerPanel.objects.select_related(
queryset = PowerPanel.objects.prefetch_related(
'site', 'rack_group'
).annotate(
rack_count=Count('powerfeeds')
@ -2310,7 +2305,7 @@ class PowerPanelBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class PowerFeedListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'dcim.view_powerfeed'
queryset = PowerFeed.objects.select_related(
queryset = PowerFeed.objects.prefetch_related(
'power_panel', 'rack'
)
filter = filters.PowerFeedFilter
@ -2324,7 +2319,7 @@ class PowerFeedView(PermissionRequiredMixin, View):
def get(self, request, pk):
powerfeed = get_object_or_404(PowerFeed.objects.select_related('power_panel', 'rack'), pk=pk)
powerfeed = get_object_or_404(PowerFeed.objects.prefetch_related('power_panel', 'rack'), pk=pk)
return render(request, 'dcim/powerfeed.html', {
'powerfeed': powerfeed,
@ -2358,7 +2353,7 @@ class PowerFeedBulkImportView(PermissionRequiredMixin, BulkImportView):
class PowerFeedBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'dcim.change_powerfeed'
queryset = PowerFeed.objects.select_related('power_panel', 'rack')
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
filter = filters.PowerFeedFilter
table = tables.PowerFeedTable
form = forms.PowerFeedBulkEditForm
@ -2367,7 +2362,7 @@ class PowerFeedBulkEditView(PermissionRequiredMixin, BulkEditView):
class PowerFeedBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'dcim.delete_powerfeed'
queryset = PowerFeed.objects.select_related('power_panel', 'rack')
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
filter = filters.PowerFeedFilter
table = tables.PowerFeedTable
default_return_url = 'dcim:powerfeed_list'

View File

@ -120,7 +120,7 @@ class ExportTemplateViewSet(ModelViewSet):
#
class TopologyMapViewSet(ModelViewSet):
queryset = TopologyMap.objects.select_related('site')
queryset = TopologyMap.objects.prefetch_related('site')
serializer_class = serializers.TopologyMapSerializer
filterset_class = filters.TopologyMapFilter
@ -260,6 +260,6 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
"""
Retrieve a list of recent changes.
"""
queryset = ObjectChange.objects.select_related('user')
queryset = ObjectChange.objects.prefetch_related('user')
serializer_class = serializers.ObjectChangeSerializer
filterset_class = filters.ObjectChangeFilter

View File

@ -111,8 +111,10 @@ class CustomFieldForm(forms.ModelForm):
# If editing an existing object, initialize values for all custom fields
if self.instance.pk:
existing_values = CustomFieldValue.objects.filter(obj_type=self.obj_type, obj_id=self.instance.pk)\
.select_related('field')
existing_values = CustomFieldValue.objects.filter(
obj_type=self.obj_type,
obj_id=self.instance.pk
).prefetch_related('field')
for cfv in existing_values:
self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.serialized_value
@ -120,9 +122,11 @@ class CustomFieldForm(forms.ModelForm):
for field_name in self.custom_fields:
try:
cfv = CustomFieldValue.objects.select_related('field').get(field=self.fields[field_name].model,
cfv = CustomFieldValue.objects.prefetch_related('field').get(
field=self.fields[field_name].model,
obj_type=self.obj_type,
obj_id=self.instance.pk)
obj_id=self.instance.pk
)
except CustomFieldValue.DoesNotExist:
# Skip this field if none exists already and its value is empty
if self.cleaned_data[field_name] in [None, '']:

View File

@ -569,7 +569,7 @@ class TopologyMap(models.Model):
# Add each device to the graph
devices = []
for query in device_set.strip(';').split(';'): # Split regexes on semicolons
devices += Device.objects.filter(name__regex=query).select_related('device_role')
devices += Device.objects.filter(name__regex=query).prefetch_related('device_role')
# Remove duplicate devices
devices = [d for d in devices if d.id not in seen]
seen.update([d.id for d in devices])
@ -607,7 +607,7 @@ class TopologyMap(models.Model):
from dcim.models import Interface
# Add all interface connections to the graph
connected_interfaces = Interface.objects.select_related(
connected_interfaces = Interface.objects.prefetch_related(
'_connected_interface__device'
).filter(
Q(device__in=devices) | Q(_connected_interface__device__in=devices),

View File

@ -47,10 +47,8 @@ class TagView(View):
tag = get_object_or_404(Tag, slug=slug)
tagged_items = TaggedItem.objects.filter(
tag=tag
).select_related(
'content_type'
).prefetch_related(
'content_object'
'content_type', 'content_object'
)
# Generate a table of all items tagged with this Tag
@ -178,7 +176,7 @@ class ObjectConfigContextView(View):
class ObjectChangeListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'extras.view_objectchange'
queryset = ObjectChange.objects.select_related('user', 'changed_object_type')
queryset = ObjectChange.objects.prefetch_related('user', 'changed_object_type')
filter = filters.ObjectChangeFilter
filter_form = ObjectChangeFilterForm
table = ObjectChangeTable
@ -217,7 +215,7 @@ class ObjectChangeLogView(View):
# Gather all changes for this object (and its related objects)
content_type = ContentType.objects.get_for_model(model)
objectchanges = ObjectChange.objects.select_related(
objectchanges = ObjectChange.objects.prefetch_related(
'user', 'changed_object_type'
).filter(
Q(changed_object_type=content_type, changed_object_id=obj.pk) |

View File

@ -33,7 +33,7 @@ class IPAMFieldChoicesViewSet(FieldChoicesViewSet):
#
class VRFViewSet(CustomFieldModelViewSet):
queryset = VRF.objects.select_related('tenant').prefetch_related('tags').annotate(
queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate(
ipaddress_count=get_subquery(IPAddress, 'vrf'),
prefix_count=get_subquery(Prefix, 'vrf')
)
@ -58,7 +58,7 @@ class RIRViewSet(ModelViewSet):
#
class AggregateViewSet(CustomFieldModelViewSet):
queryset = Aggregate.objects.select_related('rir').prefetch_related('tags')
queryset = Aggregate.objects.prefetch_related('rir').prefetch_related('tags')
serializer_class = serializers.AggregateSerializer
filterset_class = filters.AggregateFilter
@ -81,11 +81,7 @@ class RoleViewSet(ModelViewSet):
#
class PrefixViewSet(CustomFieldModelViewSet):
queryset = Prefix.objects.select_related(
'site', 'vrf__tenant', 'tenant', 'vlan', 'role'
).prefetch_related(
'tags'
)
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role', 'tags')
serializer_class = serializers.PrefixSerializer
filterset_class = filters.PrefixFilter
@ -263,9 +259,8 @@ class PrefixViewSet(CustomFieldModelViewSet):
#
class IPAddressViewSet(CustomFieldModelViewSet):
queryset = IPAddress.objects.select_related(
'vrf__tenant', 'tenant', 'nat_inside', 'interface__device__device_type', 'interface__virtual_machine'
).prefetch_related(
queryset = IPAddress.objects.prefetch_related(
'vrf__tenant', 'tenant', 'nat_inside', 'interface__device__device_type', 'interface__virtual_machine',
'nat_outside', 'tags',
)
serializer_class = serializers.IPAddressSerializer
@ -277,7 +272,7 @@ class IPAddressViewSet(CustomFieldModelViewSet):
#
class VLANGroupViewSet(ModelViewSet):
queryset = VLANGroup.objects.select_related('site').annotate(
queryset = VLANGroup.objects.prefetch_related('site').annotate(
vlan_count=Count('vlans')
)
serializer_class = serializers.VLANGroupSerializer
@ -289,10 +284,8 @@ class VLANGroupViewSet(ModelViewSet):
#
class VLANViewSet(CustomFieldModelViewSet):
queryset = VLAN.objects.select_related(
'site', 'group', 'tenant', 'role'
).prefetch_related(
'tags'
queryset = VLAN.objects.prefetch_related(
'site', 'group', 'tenant', 'role', 'tags'
).annotate(
prefix_count=get_subquery(Prefix, 'role')
)
@ -305,6 +298,6 @@ class VLANViewSet(CustomFieldModelViewSet):
#
class ServiceViewSet(ModelViewSet):
queryset = Service.objects.select_related('device').prefetch_related('tags')
queryset = Service.objects.prefetch_related('device').prefetch_related('tags')
serializer_class = serializers.ServiceSerializer
filterset_class = filters.ServiceFilter

View File

@ -360,7 +360,7 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet):
def filter_device(self, queryset, name, value):
try:
device = Device.objects.select_related('device_type').get(**{name: value})
device = Device.objects.prefetch_related('device_type').get(**{name: value})
vc_interface_ids = [i['id'] for i in device.vc_interfaces.values('id')]
return queryset.filter(interface_id__in=vc_interface_ids)
except Device.DoesNotExist:

View File

@ -115,7 +115,7 @@ def add_available_vlans(vlan_group, vlans):
class VRFListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_vrf'
queryset = VRF.objects.select_related('tenant')
queryset = VRF.objects.prefetch_related('tenant')
filter = filters.VRFFilter
filter_form = forms.VRFFilterForm
table = tables.VRFTable
@ -163,7 +163,7 @@ class VRFBulkImportView(PermissionRequiredMixin, BulkImportView):
class VRFBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_vrf'
queryset = VRF.objects.select_related('tenant')
queryset = VRF.objects.prefetch_related('tenant')
filter = filters.VRFFilter
table = tables.VRFTable
form = forms.VRFBulkEditForm
@ -172,7 +172,7 @@ class VRFBulkEditView(PermissionRequiredMixin, BulkEditView):
class VRFBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_vrf'
queryset = VRF.objects.select_related('tenant')
queryset = VRF.objects.prefetch_related('tenant')
filter = filters.VRFFilter
table = tables.VRFTable
default_return_url = 'ipam:vrf_list'
@ -291,7 +291,7 @@ class RIRBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class AggregateListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_aggregate'
queryset = Aggregate.objects.select_related('rir').extra(select={
queryset = Aggregate.objects.prefetch_related('rir').extra(select={
'child_count': 'SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix',
})
filter = filters.AggregateFilter
@ -326,7 +326,7 @@ class AggregateView(PermissionRequiredMixin, View):
# Find all child prefixes contained by this aggregate
child_prefixes = Prefix.objects.filter(
prefix__net_contained_or_equal=str(aggregate.prefix)
).select_related(
).prefetch_related(
'site', 'role'
).annotate_depth(
limit=0
@ -384,7 +384,7 @@ class AggregateBulkImportView(PermissionRequiredMixin, BulkImportView):
class AggregateBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_aggregate'
queryset = Aggregate.objects.select_related('rir')
queryset = Aggregate.objects.prefetch_related('rir')
filter = filters.AggregateFilter
table = tables.AggregateTable
form = forms.AggregateBulkEditForm
@ -393,7 +393,7 @@ class AggregateBulkEditView(PermissionRequiredMixin, BulkEditView):
class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_aggregate'
queryset = Aggregate.objects.select_related('rir')
queryset = Aggregate.objects.prefetch_related('rir')
filter = filters.AggregateFilter
table = tables.AggregateTable
default_return_url = 'ipam:aggregate_list'
@ -441,7 +441,7 @@ class RoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class PrefixListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_prefix'
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
filter = filters.PrefixFilter
filter_form = forms.PrefixFilterForm
table = tables.PrefixDetailTable
@ -458,7 +458,7 @@ class PrefixView(PermissionRequiredMixin, View):
def get(self, request, pk):
prefix = get_object_or_404(Prefix.objects.select_related(
prefix = get_object_or_404(Prefix.objects.prefetch_related(
'vrf', 'site__region', 'tenant__group', 'vlan__group', 'role'
), pk=pk)
@ -472,7 +472,7 @@ class PrefixView(PermissionRequiredMixin, View):
Q(vrf=prefix.vrf) | Q(vrf__isnull=True)
).filter(
prefix__net_contains=str(prefix.prefix)
).select_related(
).prefetch_related(
'site', 'role'
).annotate_depth()
parent_prefix_table = tables.PrefixTable(list(parent_prefixes), orderable=False)
@ -483,7 +483,7 @@ class PrefixView(PermissionRequiredMixin, View):
vrf=prefix.vrf, prefix=str(prefix.prefix)
).exclude(
pk=prefix.pk
).select_related(
).prefetch_related(
'site', 'role'
)
duplicate_prefix_table = tables.PrefixTable(list(duplicate_prefixes), orderable=False)
@ -505,7 +505,7 @@ class PrefixPrefixesView(PermissionRequiredMixin, View):
prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
# Child prefixes table
child_prefixes = prefix.get_child_prefixes().select_related(
child_prefixes = prefix.get_child_prefixes().prefetch_related(
'site', 'vlan', 'role',
).annotate_depth(limit=0)
@ -548,7 +548,7 @@ class PrefixIPAddressesView(PermissionRequiredMixin, View):
prefix = get_object_or_404(Prefix.objects.all(), pk=pk)
# Find all IPAddresses belonging to this Prefix
ipaddresses = prefix.get_child_ips().select_related(
ipaddresses = prefix.get_child_ips().prefetch_related(
'vrf', 'interface__device', 'primary_ip4_for', 'primary_ip6_for'
)
ipaddresses = add_available_ipaddresses(prefix.prefix, ipaddresses, prefix.is_pool)
@ -608,7 +608,7 @@ class PrefixBulkImportView(PermissionRequiredMixin, BulkImportView):
class PrefixBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_prefix'
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
filter = filters.PrefixFilter
table = tables.PrefixTable
form = forms.PrefixBulkEditForm
@ -617,7 +617,7 @@ class PrefixBulkEditView(PermissionRequiredMixin, BulkEditView):
class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_prefix'
queryset = Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
filter = filters.PrefixFilter
table = tables.PrefixTable
default_return_url = 'ipam:prefix_list'
@ -629,10 +629,8 @@ class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class IPAddressListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_ipaddress'
queryset = IPAddress.objects.select_related(
'vrf__tenant', 'tenant', 'nat_inside'
).prefetch_related(
'interface__device', 'interface__virtual_machine'
queryset = IPAddress.objects.prefetch_related(
'vrf__tenant', 'tenant', 'nat_inside', 'interface__device', 'interface__virtual_machine'
)
filter = filters.IPAddressFilter
filter_form = forms.IPAddressFilterForm
@ -645,12 +643,12 @@ class IPAddressView(PermissionRequiredMixin, View):
def get(self, request, pk):
ipaddress = get_object_or_404(IPAddress.objects.select_related('vrf__tenant', 'tenant'), pk=pk)
ipaddress = get_object_or_404(IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'), pk=pk)
# Parent prefixes table
parent_prefixes = Prefix.objects.filter(
vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip)
).select_related(
).prefetch_related(
'site', 'role'
)
parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False)
@ -661,10 +659,8 @@ class IPAddressView(PermissionRequiredMixin, View):
vrf=ipaddress.vrf, address=str(ipaddress.address)
).exclude(
pk=ipaddress.pk
).select_related(
'nat_inside'
).prefetch_related(
'interface__device'
'nat_inside', 'interface__device'
)
# Exclude anycast IPs if this IP is anycast
if ipaddress.role == IPADDRESS_ROLE_ANYCAST:
@ -742,7 +738,7 @@ class IPAddressAssignView(PermissionRequiredMixin, View):
if form.is_valid():
queryset = IPAddress.objects.select_related(
queryset = IPAddress.objects.prefetch_related(
'vrf', 'tenant', 'interface__device', 'interface__virtual_machine'
).filter(
vrf=form.cleaned_data['vrf'],
@ -781,7 +777,7 @@ class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_ipaddress'
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
filter = filters.IPAddressFilter
table = tables.IPAddressTable
form = forms.IPAddressBulkEditForm
@ -790,7 +786,7 @@ class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_ipaddress'
queryset = IPAddress.objects.select_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant').prefetch_related('interface__device')
filter = filters.IPAddressFilter
table = tables.IPAddressTable
default_return_url = 'ipam:ipaddress_list'
@ -802,7 +798,7 @@ class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class VLANGroupListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_vlangroup'
queryset = VLANGroup.objects.select_related('site').annotate(vlan_count=Count('vlans'))
queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans'))
filter = filters.VLANGroupFilter
filter_form = forms.VLANGroupFilterForm
table = tables.VLANGroupTable
@ -829,7 +825,7 @@ class VLANGroupBulkImportView(PermissionRequiredMixin, BulkImportView):
class VLANGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_vlangroup'
queryset = VLANGroup.objects.select_related('site').annotate(vlan_count=Count('vlans'))
queryset = VLANGroup.objects.prefetch_related('site').annotate(vlan_count=Count('vlans'))
filter = filters.VLANGroupFilter
table = tables.VLANGroupTable
default_return_url = 'ipam:vlangroup_list'
@ -878,7 +874,7 @@ class VLANGroupVLANsView(PermissionRequiredMixin, View):
class VLANListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_vlan'
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('prefixes')
queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role').prefetch_related('prefixes')
filter = filters.VLANFilter
filter_form = forms.VLANFilterForm
table = tables.VLANDetailTable
@ -890,10 +886,10 @@ class VLANView(PermissionRequiredMixin, View):
def get(self, request, pk):
vlan = get_object_or_404(VLAN.objects.select_related(
vlan = get_object_or_404(VLAN.objects.prefetch_related(
'site__region', 'tenant__group', 'role'
), pk=pk)
prefixes = Prefix.objects.filter(vlan=vlan).select_related('vrf', 'site', 'role')
prefixes = Prefix.objects.filter(vlan=vlan).prefetch_related('vrf', 'site', 'role')
prefix_table = tables.PrefixTable(list(prefixes), orderable=False)
prefix_table.exclude = ('vlan',)
@ -909,7 +905,7 @@ class VLANMembersView(PermissionRequiredMixin, View):
def get(self, request, pk):
vlan = get_object_or_404(VLAN.objects.all(), pk=pk)
members = vlan.get_members().select_related('device', 'virtual_machine')
members = vlan.get_members().prefetch_related('device', 'virtual_machine')
members_table = tables.VLANMemberTable(members)
@ -953,7 +949,7 @@ class VLANBulkImportView(PermissionRequiredMixin, BulkImportView):
class VLANBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_vlan'
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
filter = filters.VLANFilter
table = tables.VLANTable
form = forms.VLANBulkEditForm
@ -962,7 +958,7 @@ class VLANBulkEditView(PermissionRequiredMixin, BulkEditView):
class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_vlan'
queryset = VLAN.objects.select_related('site', 'group', 'tenant', 'role')
queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
filter = filters.VLANFilter
table = tables.VLANTable
default_return_url = 'ipam:vlan_list'
@ -974,7 +970,7 @@ class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class ServiceListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'ipam.view_service'
queryset = Service.objects.select_related('device', 'virtual_machine')
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filter = filters.ServiceFilter
filter_form = forms.ServiceFilterForm
table = tables.ServiceTable
@ -1021,7 +1017,7 @@ class ServiceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
class ServiceBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'ipam.change_service'
queryset = Service.objects.select_related('device', 'virtual_machine')
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filter = filters.ServiceFilter
table = tables.ServiceTable
form = forms.ServiceBulkEditForm
@ -1030,7 +1026,7 @@ class ServiceBulkEditView(PermissionRequiredMixin, BulkEditView):
class ServiceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_service'
queryset = Service.objects.select_related('device', 'virtual_machine')
queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filter = filters.ServiceFilter
table = tables.ServiceTable
default_return_url = 'ipam:service_list'

View File

@ -37,7 +37,7 @@ class TokenAuthentication(authentication.TokenAuthentication):
def authenticate_credentials(self, key):
model = self.get_model()
try:
token = model.objects.select_related('user').get(key=key)
token = model.objects.prefetch_related('user').get(key=key)
except model.DoesNotExist:
raise exceptions.AuthenticationFailed("Invalid token")

View File

@ -46,38 +46,38 @@ SEARCH_TYPES = OrderedDict((
'url': 'circuits:provider_list',
}),
('circuit', {
'queryset': Circuit.objects.select_related('type', 'provider', 'tenant').prefetch_related('terminations__site'),
'queryset': Circuit.objects.prefetch_related('type', 'provider', 'tenant').prefetch_related('terminations__site'),
'filter': CircuitFilter,
'table': CircuitTable,
'url': 'circuits:circuit_list',
}),
# DCIM
('site', {
'queryset': Site.objects.select_related('region', 'tenant'),
'queryset': Site.objects.prefetch_related('region', 'tenant'),
'filter': SiteFilter,
'table': SiteTable,
'url': 'dcim:site_list',
}),
('rack', {
'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'),
'queryset': Rack.objects.prefetch_related('site', 'group', 'tenant', 'role'),
'filter': RackFilter,
'table': RackTable,
'url': 'dcim:rack_list',
}),
('rackgroup', {
'queryset': RackGroup.objects.select_related('site').annotate(rack_count=Count('racks')),
'queryset': RackGroup.objects.prefetch_related('site').annotate(rack_count=Count('racks')),
'filter': RackGroupFilter,
'table': RackGroupTable,
'url': 'dcim:rackgroup_list',
}),
('devicetype', {
'queryset': DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances')),
'queryset': DeviceType.objects.prefetch_related('manufacturer').annotate(instance_count=Count('instances')),
'filter': DeviceTypeFilter,
'table': DeviceTypeTable,
'url': 'dcim:devicetype_list',
}),
('device', {
'queryset': Device.objects.select_related(
'queryset': Device.objects.prefetch_related(
'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6',
),
'filter': DeviceFilter,
@ -85,7 +85,7 @@ SEARCH_TYPES = OrderedDict((
'url': 'dcim:device_list',
}),
('virtualchassis', {
'queryset': VirtualChassis.objects.select_related('master').annotate(member_count=Count('members')),
'queryset': VirtualChassis.objects.prefetch_related('master').annotate(member_count=Count('members')),
'filter': VirtualChassisFilter,
'table': VirtualChassisTable,
'url': 'dcim:virtualchassis_list',
@ -104,58 +104,58 @@ SEARCH_TYPES = OrderedDict((
}),
# IPAM
('vrf', {
'queryset': VRF.objects.select_related('tenant'),
'queryset': VRF.objects.prefetch_related('tenant'),
'filter': VRFFilter,
'table': VRFTable,
'url': 'ipam:vrf_list',
}),
('aggregate', {
'queryset': Aggregate.objects.select_related('rir'),
'queryset': Aggregate.objects.prefetch_related('rir'),
'filter': AggregateFilter,
'table': AggregateTable,
'url': 'ipam:aggregate_list',
}),
('prefix', {
'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
'filter': PrefixFilter,
'table': PrefixTable,
'url': 'ipam:prefix_list',
}),
('ipaddress', {
'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant'),
'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'),
'filter': IPAddressFilter,
'table': IPAddressTable,
'url': 'ipam:ipaddress_list',
}),
('vlan', {
'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'),
'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'),
'filter': VLANFilter,
'table': VLANTable,
'url': 'ipam:vlan_list',
}),
# Secrets
('secret', {
'queryset': Secret.objects.select_related('role', 'device'),
'queryset': Secret.objects.prefetch_related('role', 'device'),
'filter': SecretFilter,
'table': SecretTable,
'url': 'secrets:secret_list',
}),
# Tenancy
('tenant', {
'queryset': Tenant.objects.select_related('group'),
'queryset': Tenant.objects.prefetch_related('group'),
'filter': TenantFilter,
'table': TenantTable,
'url': 'tenancy:tenant_list',
}),
# Virtualization
('cluster', {
'queryset': Cluster.objects.select_related('type', 'group'),
'queryset': Cluster.objects.prefetch_related('type', 'group'),
'filter': ClusterFilter,
'table': ClusterTable,
'url': 'virtualization:cluster_list',
}),
('virtualmachine', {
'queryset': VirtualMachine.objects.select_related(
'queryset': VirtualMachine.objects.prefetch_related(
'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6',
),
'filter': VirtualMachineFilter,
@ -224,7 +224,7 @@ class HomeView(View):
'stats': stats,
'topology_maps': TopologyMap.objects.filter(site__isnull=True),
'report_results': ReportResult.objects.order_by('-created')[:10],
'changelog': ObjectChange.objects.select_related('user', 'changed_object_type')[:50]
'changelog': ObjectChange.objects.prefetch_related('user', 'changed_object_type')[:50]
})

View File

@ -46,10 +46,8 @@ class SecretRoleViewSet(ModelViewSet):
#
class SecretViewSet(ModelViewSet):
queryset = Secret.objects.select_related(
'device__primary_ip4', 'device__primary_ip6', 'role',
).prefetch_related(
'role__users', 'role__groups', 'tags',
queryset = Secret.objects.prefetch_related(
'device__primary_ip4', 'device__primary_ip6', 'role', 'role__users', 'role__groups', 'tags',
)
serializer_class = serializers.SecretSerializer
filterset_class = filters.SecretFilter

View File

@ -69,7 +69,7 @@ class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class SecretListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'secrets.view_secret'
queryset = Secret.objects.select_related('role', 'device')
queryset = Secret.objects.prefetch_related('role', 'device')
filter = filters.SecretFilter
filter_form = forms.SecretFilterForm
table = tables.SecretTable
@ -247,7 +247,7 @@ class SecretBulkImportView(BulkImportView):
class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'secrets.change_secret'
queryset = Secret.objects.select_related('role', 'device')
queryset = Secret.objects.prefetch_related('role', 'device')
filter = filters.SecretFilter
table = tables.SecretTable
form = forms.SecretBulkEditForm
@ -256,7 +256,7 @@ class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
class SecretBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'secrets.delete_secret'
queryset = Secret.objects.select_related('role', 'device')
queryset = Secret.objects.prefetch_related('role', 'device')
filter = filters.SecretFilter
table = tables.SecretTable
default_return_url = 'secrets:secret_list'

View File

@ -35,10 +35,8 @@ class TenantGroupViewSet(ModelViewSet):
#
class TenantViewSet(CustomFieldModelViewSet):
queryset = Tenant.objects.select_related(
'group'
).prefetch_related(
'tags'
queryset = Tenant.objects.prefetch_related(
'group', 'tags'
).annotate(
circuit_count=get_subquery(Circuit, 'tenant'),
device_count=get_subquery(Device, 'tenant'),

View File

@ -56,7 +56,7 @@ class TenantGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class TenantListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'tenancy.view_tenant'
queryset = Tenant.objects.select_related('group')
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
filter_form = forms.TenantFilterForm
table = tables.TenantTable
@ -115,7 +115,7 @@ class TenantBulkImportView(PermissionRequiredMixin, BulkImportView):
class TenantBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'tenancy.change_tenant'
queryset = Tenant.objects.select_related('group')
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
table = tables.TenantTable
form = forms.TenantBulkEditForm
@ -124,7 +124,7 @@ class TenantBulkEditView(PermissionRequiredMixin, BulkEditView):
class TenantBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'tenancy.delete_tenant'
queryset = Tenant.objects.select_related('group')
queryset = Tenant.objects.prefetch_related('group')
filter = filters.TenantFilter
table = tables.TenantTable
default_return_url = 'tenancy:tenant_list'

View File

@ -40,10 +40,8 @@ class ClusterGroupViewSet(ModelViewSet):
class ClusterViewSet(CustomFieldModelViewSet):
queryset = Cluster.objects.select_related(
'type', 'group', 'site',
).prefetch_related(
'tags'
queryset = Cluster.objects.prefetch_related(
'type', 'group', 'site', 'tags'
).annotate(
device_count=get_subquery(Device, 'cluster'),
virtualmachine_count=get_subquery(VirtualMachine, 'cluster')
@ -57,9 +55,9 @@ class ClusterViewSet(CustomFieldModelViewSet):
#
class VirtualMachineViewSet(CustomFieldModelViewSet):
queryset = VirtualMachine.objects.select_related(
'cluster__site', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6'
).prefetch_related('tags')
queryset = VirtualMachine.objects.prefetch_related(
'cluster__site', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'tags'
)
filterset_class = filters.VirtualMachineFilter
def get_serializer_class(self):
@ -86,7 +84,9 @@ class VirtualMachineViewSet(CustomFieldModelViewSet):
class InterfaceViewSet(ModelViewSet):
queryset = Interface.objects.filter(
virtual_machine__isnull=False
).select_related('virtual_machine').prefetch_related('tags')
).prefetch_related(
'virtual_machine', 'tags'
)
serializer_class = serializers.InterfaceSerializer
filterset_class = filters.InterfaceFilter

View File

@ -376,7 +376,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
for family in [4, 6]:
ip_choices = [(None, '---------')]
# Collect interface IPs
interface_ips = IPAddress.objects.select_related('interface').filter(
interface_ips = IPAddress.objects.prefetch_related('interface').filter(
family=family, interface__virtual_machine=self.instance
)
if interface_ips:
@ -386,7 +386,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
])
)
# Collect NAT IPs
nat_ips = IPAddress.objects.select_related('nat_inside').filter(
nat_ips = IPAddress.objects.prefetch_related('nat_inside').filter(
family=family, nat_inside__interface__virtual_machine=self.instance
)
if nat_ips:

View File

@ -96,7 +96,7 @@ class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class ClusterListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'virtualization.view_cluster'
queryset = Cluster.objects.select_related('type', 'group', 'site')
queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
table = tables.ClusterTable
filter = filters.ClusterFilter
filter_form = forms.ClusterFilterForm
@ -109,7 +109,7 @@ class ClusterView(PermissionRequiredMixin, View):
def get(self, request, pk):
cluster = get_object_or_404(Cluster, pk=pk)
devices = Device.objects.filter(cluster=cluster).select_related(
devices = Device.objects.filter(cluster=cluster).prefetch_related(
'site', 'rack', 'tenant', 'device_type__manufacturer'
)
device_table = DeviceTable(list(devices), orderable=False)
@ -148,7 +148,7 @@ class ClusterBulkImportView(PermissionRequiredMixin, BulkImportView):
class ClusterBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'virtualization.change_cluster'
queryset = Cluster.objects.select_related('type', 'group', 'site')
queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
filter = filters.ClusterFilter
table = tables.ClusterTable
form = forms.ClusterBulkEditForm
@ -157,7 +157,7 @@ class ClusterBulkEditView(PermissionRequiredMixin, BulkEditView):
class ClusterBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'virtualization.delete_cluster'
queryset = Cluster.objects.select_related('type', 'group', 'site')
queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
filter = filters.ClusterFilter
table = tables.ClusterTable
default_return_url = 'virtualization:cluster_list'
@ -253,7 +253,7 @@ class ClusterRemoveDevicesView(PermissionRequiredMixin, View):
class VirtualMachineListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'virtualization.view_virtualmachine'
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role', 'primary_ip4', 'primary_ip6')
filter = filters.VirtualMachineFilter
filter_form = forms.VirtualMachineFilterForm
table = tables.VirtualMachineDetailTable
@ -265,7 +265,7 @@ class VirtualMachineView(PermissionRequiredMixin, View):
def get(self, request, pk):
virtualmachine = get_object_or_404(VirtualMachine.objects.select_related('tenant__group'), pk=pk)
virtualmachine = get_object_or_404(VirtualMachine.objects.prefetch_related('tenant__group'), pk=pk)
interfaces = Interface.objects.filter(virtual_machine=virtualmachine)
services = Service.objects.filter(virtual_machine=virtualmachine)
@ -309,7 +309,7 @@ class VirtualMachineBulkImportView(PermissionRequiredMixin, BulkImportView):
class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'virtualization.change_virtualmachine'
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
filter = filters.VirtualMachineFilter
table = tables.VirtualMachineTable
form = forms.VirtualMachineBulkEditForm
@ -318,7 +318,7 @@ class VirtualMachineBulkEditView(PermissionRequiredMixin, BulkEditView):
class VirtualMachineBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'virtualization.delete_virtualmachine'
queryset = VirtualMachine.objects.select_related('cluster', 'tenant', 'role')
queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
filter = filters.VirtualMachineFilter
table = tables.VirtualMachineTable
default_return_url = 'virtualization:virtualmachine_list'