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): def test_console_connection(self):
# Check that every console port for every active device has a connection defined. # 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: if console_port.connected_endpoint is None:
self.log_failure( self.log_failure(
console_port.device, 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 ### 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 ### 5. Update API serializer

View File

@ -62,7 +62,7 @@ class CircuitTypeViewSet(ModelViewSet):
# #
class CircuitViewSet(CustomFieldModelViewSet): 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 serializer_class = serializers.CircuitSerializer
filterset_class = filters.CircuitFilter filterset_class = filters.CircuitFilter
@ -72,7 +72,7 @@ class CircuitViewSet(CustomFieldModelViewSet):
# #
class CircuitTerminationViewSet(ModelViewSet): class CircuitTerminationViewSet(ModelViewSet):
queryset = CircuitTermination.objects.select_related( queryset = CircuitTermination.objects.prefetch_related(
'circuit', 'site', 'connected_endpoint__device', 'cable' 'circuit', 'site', 'connected_endpoint__device', 'cable'
) )
serializer_class = serializers.CircuitTerminationSerializer serializer_class = serializers.CircuitTerminationSerializer

View File

@ -295,6 +295,6 @@ class CircuitTermination(CableTermination):
def get_peer_termination(self): def get_peer_termination(self):
peer_side = 'Z' if self.term_side == 'A' else 'A' peer_side = 'Z' if self.term_side == 'A' else 'A'
try: 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: except CircuitTermination.DoesNotExist:
return None 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. 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): def get(self, request, slug):
provider = get_object_or_404(Provider, slug=slug) provider = get_object_or_404(Provider, slug=slug)
circuits = Circuit.objects.filter(provider=provider).select_related( circuits = Circuit.objects.filter(provider=provider).prefetch_related('type', 'tenant', 'terminations__site')
'type', 'tenant'
).prefetch_related(
'terminations__site'
)
show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists() show_graphs = Graph.objects.filter(type=GRAPH_TYPE_PROVIDER).exists()
return render(request, 'circuits/provider.html', { return render(request, 'circuits/provider.html', {
@ -134,10 +130,8 @@ class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class CircuitListView(PermissionRequiredMixin, ObjectListView): class CircuitListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'circuits.view_circuit' permission_required = 'circuits.view_circuit'
_terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk')) _terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
queryset = Circuit.objects.select_related( queryset = Circuit.objects.prefetch_related(
'provider', 'type', 'tenant' 'provider', 'type', 'tenant', 'terminations__site'
).prefetch_related(
'terminations__site'
).annotate( ).annotate(
a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]), a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),
z_side=Subquery(_terminations.filter(term_side='Z').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): def get(self, request, pk):
circuit = get_object_or_404(Circuit.objects.select_related('provider', 'type', 'tenant__group'), pk=pk) circuit = get_object_or_404(Circuit.objects.prefetch_related('provider', 'type', 'tenant__group'), pk=pk)
termination_a = CircuitTermination.objects.select_related( termination_a = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device' 'site__region', 'connected_endpoint__device'
).filter( ).filter(
circuit=circuit, term_side=TERM_SIDE_A circuit=circuit, term_side=TERM_SIDE_A
).first() ).first()
termination_z = CircuitTermination.objects.select_related( termination_z = CircuitTermination.objects.prefetch_related(
'site__region', 'connected_endpoint__device' 'site__region', 'connected_endpoint__device'
).filter( ).filter(
circuit=circuit, term_side=TERM_SIDE_Z circuit=circuit, term_side=TERM_SIDE_Z
@ -199,7 +193,7 @@ class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView): class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'circuits.change_circuit' 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 filter = filters.CircuitFilter
table = tables.CircuitTable table = tables.CircuitTable
form = forms.CircuitBulkEditForm form = forms.CircuitBulkEditForm
@ -208,7 +202,7 @@ class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'circuits.delete_circuit' 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 filter = filters.CircuitFilter
table = tables.CircuitTable table = tables.CircuitTable
default_return_url = 'circuits:circuit_list' default_return_url = 'circuits:circuit_list'

View File

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

View File

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

View File

@ -607,7 +607,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
# Update racked devices if the assigned Site has been changed. # Update racked devices if the assigned Site has been changed.
if _site_id is not None and self.site_id != _site_id: 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): def to_csv(self):
return ( return (
@ -664,7 +664,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
# Add devices to rack units list # Add devices to rack units list
if self.pk: 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'))\ .annotate(devicebay_count=Count('device_bays'))\
.exclude(pk=exclude)\ .exclude(pk=exclude)\
.filter(rack=self, position__gt=0)\ .filter(rack=self, position__gt=0)\
@ -697,7 +697,7 @@ class Rack(ChangeLoggedModel, CustomFieldModel):
""" """
# Gather all devices which consume U space within the rack # 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 # Initialize the rack unit skeleton
units = list(range(1, self.u_height + 1)) 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 # 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): def to_csv(self):
return ( 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. When a VirtualChassis is created, automatically assign its master device to the VC.
""" """
if created: 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) @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. 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) @receiver(post_save, sender=Cable)

View File

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

View File

@ -442,11 +442,11 @@ class VirtualChassisTestCase(TestCase):
# Create three VirtualChassis with two members each # Create three VirtualChassis with two members each
vc1 = VirtualChassis.objects.create(master=device1, domain='test-domain-1') 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') 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') 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): def test_virtualchassis_list(self):

View File

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

View File

@ -120,7 +120,7 @@ class ExportTemplateViewSet(ModelViewSet):
# #
class TopologyMapViewSet(ModelViewSet): class TopologyMapViewSet(ModelViewSet):
queryset = TopologyMap.objects.select_related('site') queryset = TopologyMap.objects.prefetch_related('site')
serializer_class = serializers.TopologyMapSerializer serializer_class = serializers.TopologyMapSerializer
filterset_class = filters.TopologyMapFilter filterset_class = filters.TopologyMapFilter
@ -260,6 +260,6 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
""" """
Retrieve a list of recent changes. Retrieve a list of recent changes.
""" """
queryset = ObjectChange.objects.select_related('user') queryset = ObjectChange.objects.prefetch_related('user')
serializer_class = serializers.ObjectChangeSerializer serializer_class = serializers.ObjectChangeSerializer
filterset_class = filters.ObjectChangeFilter 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 editing an existing object, initialize values for all custom fields
if self.instance.pk: if self.instance.pk:
existing_values = CustomFieldValue.objects.filter(obj_type=self.obj_type, obj_id=self.instance.pk)\ existing_values = CustomFieldValue.objects.filter(
.select_related('field') obj_type=self.obj_type,
obj_id=self.instance.pk
).prefetch_related('field')
for cfv in existing_values: for cfv in existing_values:
self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.serialized_value 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: for field_name in self.custom_fields:
try: try:
cfv = CustomFieldValue.objects.select_related('field').get(field=self.fields[field_name].model, cfv = CustomFieldValue.objects.prefetch_related('field').get(
obj_type=self.obj_type, field=self.fields[field_name].model,
obj_id=self.instance.pk) obj_type=self.obj_type,
obj_id=self.instance.pk
)
except CustomFieldValue.DoesNotExist: except CustomFieldValue.DoesNotExist:
# Skip this field if none exists already and its value is empty # Skip this field if none exists already and its value is empty
if self.cleaned_data[field_name] in [None, '']: if self.cleaned_data[field_name] in [None, '']:

View File

@ -569,7 +569,7 @@ class TopologyMap(models.Model):
# Add each device to the graph # Add each device to the graph
devices = [] devices = []
for query in device_set.strip(';').split(';'): # Split regexes on semicolons 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 # Remove duplicate devices
devices = [d for d in devices if d.id not in seen] devices = [d for d in devices if d.id not in seen]
seen.update([d.id for d in devices]) seen.update([d.id for d in devices])
@ -607,7 +607,7 @@ class TopologyMap(models.Model):
from dcim.models import Interface from dcim.models import Interface
# Add all interface connections to the graph # Add all interface connections to the graph
connected_interfaces = Interface.objects.select_related( connected_interfaces = Interface.objects.prefetch_related(
'_connected_interface__device' '_connected_interface__device'
).filter( ).filter(
Q(device__in=devices) | Q(_connected_interface__device__in=devices), 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) tag = get_object_or_404(Tag, slug=slug)
tagged_items = TaggedItem.objects.filter( tagged_items = TaggedItem.objects.filter(
tag=tag tag=tag
).select_related(
'content_type'
).prefetch_related( ).prefetch_related(
'content_object' 'content_type', 'content_object'
) )
# Generate a table of all items tagged with this Tag # Generate a table of all items tagged with this Tag
@ -178,7 +176,7 @@ class ObjectConfigContextView(View):
class ObjectChangeListView(PermissionRequiredMixin, ObjectListView): class ObjectChangeListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'extras.view_objectchange' 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 = filters.ObjectChangeFilter
filter_form = ObjectChangeFilterForm filter_form = ObjectChangeFilterForm
table = ObjectChangeTable table = ObjectChangeTable
@ -217,7 +215,7 @@ class ObjectChangeLogView(View):
# Gather all changes for this object (and its related objects) # Gather all changes for this object (and its related objects)
content_type = ContentType.objects.get_for_model(model) content_type = ContentType.objects.get_for_model(model)
objectchanges = ObjectChange.objects.select_related( objectchanges = ObjectChange.objects.prefetch_related(
'user', 'changed_object_type' 'user', 'changed_object_type'
).filter( ).filter(
Q(changed_object_type=content_type, changed_object_id=obj.pk) | Q(changed_object_type=content_type, changed_object_id=obj.pk) |

View File

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

View File

@ -360,7 +360,7 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet):
def filter_device(self, queryset, name, value): def filter_device(self, queryset, name, value):
try: 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')] vc_interface_ids = [i['id'] for i in device.vc_interfaces.values('id')]
return queryset.filter(interface_id__in=vc_interface_ids) return queryset.filter(interface_id__in=vc_interface_ids)
except Device.DoesNotExist: except Device.DoesNotExist:

View File

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

View File

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

View File

@ -46,38 +46,38 @@ SEARCH_TYPES = OrderedDict((
'url': 'circuits:provider_list', 'url': 'circuits:provider_list',
}), }),
('circuit', { ('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, 'filter': CircuitFilter,
'table': CircuitTable, 'table': CircuitTable,
'url': 'circuits:circuit_list', 'url': 'circuits:circuit_list',
}), }),
# DCIM # DCIM
('site', { ('site', {
'queryset': Site.objects.select_related('region', 'tenant'), 'queryset': Site.objects.prefetch_related('region', 'tenant'),
'filter': SiteFilter, 'filter': SiteFilter,
'table': SiteTable, 'table': SiteTable,
'url': 'dcim:site_list', 'url': 'dcim:site_list',
}), }),
('rack', { ('rack', {
'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'), 'queryset': Rack.objects.prefetch_related('site', 'group', 'tenant', 'role'),
'filter': RackFilter, 'filter': RackFilter,
'table': RackTable, 'table': RackTable,
'url': 'dcim:rack_list', 'url': 'dcim:rack_list',
}), }),
('rackgroup', { ('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, 'filter': RackGroupFilter,
'table': RackGroupTable, 'table': RackGroupTable,
'url': 'dcim:rackgroup_list', 'url': 'dcim:rackgroup_list',
}), }),
('devicetype', { ('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, 'filter': DeviceTypeFilter,
'table': DeviceTypeTable, 'table': DeviceTypeTable,
'url': 'dcim:devicetype_list', 'url': 'dcim:devicetype_list',
}), }),
('device', { ('device', {
'queryset': Device.objects.select_related( 'queryset': Device.objects.prefetch_related(
'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6', 'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6',
), ),
'filter': DeviceFilter, 'filter': DeviceFilter,
@ -85,7 +85,7 @@ SEARCH_TYPES = OrderedDict((
'url': 'dcim:device_list', 'url': 'dcim:device_list',
}), }),
('virtualchassis', { ('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, 'filter': VirtualChassisFilter,
'table': VirtualChassisTable, 'table': VirtualChassisTable,
'url': 'dcim:virtualchassis_list', 'url': 'dcim:virtualchassis_list',
@ -104,58 +104,58 @@ SEARCH_TYPES = OrderedDict((
}), }),
# IPAM # IPAM
('vrf', { ('vrf', {
'queryset': VRF.objects.select_related('tenant'), 'queryset': VRF.objects.prefetch_related('tenant'),
'filter': VRFFilter, 'filter': VRFFilter,
'table': VRFTable, 'table': VRFTable,
'url': 'ipam:vrf_list', 'url': 'ipam:vrf_list',
}), }),
('aggregate', { ('aggregate', {
'queryset': Aggregate.objects.select_related('rir'), 'queryset': Aggregate.objects.prefetch_related('rir'),
'filter': AggregateFilter, 'filter': AggregateFilter,
'table': AggregateTable, 'table': AggregateTable,
'url': 'ipam:aggregate_list', 'url': 'ipam:aggregate_list',
}), }),
('prefix', { ('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, 'filter': PrefixFilter,
'table': PrefixTable, 'table': PrefixTable,
'url': 'ipam:prefix_list', 'url': 'ipam:prefix_list',
}), }),
('ipaddress', { ('ipaddress', {
'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant'), 'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'),
'filter': IPAddressFilter, 'filter': IPAddressFilter,
'table': IPAddressTable, 'table': IPAddressTable,
'url': 'ipam:ipaddress_list', 'url': 'ipam:ipaddress_list',
}), }),
('vlan', { ('vlan', {
'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'), 'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'),
'filter': VLANFilter, 'filter': VLANFilter,
'table': VLANTable, 'table': VLANTable,
'url': 'ipam:vlan_list', 'url': 'ipam:vlan_list',
}), }),
# Secrets # Secrets
('secret', { ('secret', {
'queryset': Secret.objects.select_related('role', 'device'), 'queryset': Secret.objects.prefetch_related('role', 'device'),
'filter': SecretFilter, 'filter': SecretFilter,
'table': SecretTable, 'table': SecretTable,
'url': 'secrets:secret_list', 'url': 'secrets:secret_list',
}), }),
# Tenancy # Tenancy
('tenant', { ('tenant', {
'queryset': Tenant.objects.select_related('group'), 'queryset': Tenant.objects.prefetch_related('group'),
'filter': TenantFilter, 'filter': TenantFilter,
'table': TenantTable, 'table': TenantTable,
'url': 'tenancy:tenant_list', 'url': 'tenancy:tenant_list',
}), }),
# Virtualization # Virtualization
('cluster', { ('cluster', {
'queryset': Cluster.objects.select_related('type', 'group'), 'queryset': Cluster.objects.prefetch_related('type', 'group'),
'filter': ClusterFilter, 'filter': ClusterFilter,
'table': ClusterTable, 'table': ClusterTable,
'url': 'virtualization:cluster_list', 'url': 'virtualization:cluster_list',
}), }),
('virtualmachine', { ('virtualmachine', {
'queryset': VirtualMachine.objects.select_related( 'queryset': VirtualMachine.objects.prefetch_related(
'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6',
), ),
'filter': VirtualMachineFilter, 'filter': VirtualMachineFilter,
@ -224,7 +224,7 @@ class HomeView(View):
'stats': stats, 'stats': stats,
'topology_maps': TopologyMap.objects.filter(site__isnull=True), 'topology_maps': TopologyMap.objects.filter(site__isnull=True),
'report_results': ReportResult.objects.order_by('-created')[:10], '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): class SecretViewSet(ModelViewSet):
queryset = Secret.objects.select_related( queryset = Secret.objects.prefetch_related(
'device__primary_ip4', 'device__primary_ip6', 'role', 'device__primary_ip4', 'device__primary_ip6', 'role', 'role__users', 'role__groups', 'tags',
).prefetch_related(
'role__users', 'role__groups', 'tags',
) )
serializer_class = serializers.SecretSerializer serializer_class = serializers.SecretSerializer
filterset_class = filters.SecretFilter filterset_class = filters.SecretFilter

View File

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

View File

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

View File

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

View File

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

View File

@ -376,7 +376,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
for family in [4, 6]: for family in [4, 6]:
ip_choices = [(None, '---------')] ip_choices = [(None, '---------')]
# Collect interface IPs # 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 family=family, interface__virtual_machine=self.instance
) )
if interface_ips: if interface_ips:
@ -386,7 +386,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
]) ])
) )
# Collect NAT IPs # 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 family=family, nat_inside__interface__virtual_machine=self.instance
) )
if nat_ips: if nat_ips:

View File

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