diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index 60bfade24..0f84ee772 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -233,8 +233,7 @@ class PrefixViewSet(CustomFieldModelViewSet): class IPAddressViewSet(CustomFieldModelViewSet): queryset = IPAddress.objects.prefetch_related( - 'vrf__tenant', 'tenant', 'nat_inside', 'interface__device__device_type', 'interface__virtual_machine', - 'nat_outside', 'tags', + 'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags', ) serializer_class = serializers.IPAddressSerializer filterset_class = filters.IPAddressFilterSet diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index 15be58ad4..aa3fa885b 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -1,5 +1,6 @@ import django_filters import netaddr +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db.models import Q from netaddr.core import AddrFormatError @@ -11,7 +12,7 @@ from utilities.filters import ( BaseFilterSet, MultiValueCharFilter, MultiValueNumberFilter, NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter, ) -from virtualization.models import VirtualMachine +from virtualization.models import Interface as VMInterface, VirtualMachine from .choices import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF @@ -299,27 +300,26 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, to_field_name='rd', label='VRF (RD)', ) - # device = MultiValueCharFilter( - # method='filter_device', - # field_name='name', - # label='Device (name)', - # ) - # device_id = MultiValueNumberFilter( - # method='filter_device', - # field_name='pk', - # label='Device (ID)', - # ) - # virtual_machine_id = django_filters.ModelMultipleChoiceFilter( - # field_name='interface__virtual_machine', - # queryset=VirtualMachine.objects.unrestricted(), - # label='Virtual machine (ID)', - # ) - # virtual_machine = django_filters.ModelMultipleChoiceFilter( - # field_name='interface__virtual_machine__name', - # queryset=VirtualMachine.objects.unrestricted(), - # to_field_name='name', - # label='Virtual machine (name)', - # ) + device = MultiValueCharFilter( + method='filter_device', + field_name='name', + label='Device (name)', + ) + device_id = MultiValueNumberFilter( + method='filter_device', + field_name='pk', + label='Device (ID)', + ) + virtual_machine = MultiValueCharFilter( + method='filter_virtual_machine', + field_name='name', + label='Virtual machine (name)', + ) + virtual_machine_id = MultiValueNumberFilter( + method='filter_virtual_machine', + field_name='pk', + label='Virtual machine (ID)', + ) # interface = django_filters.ModelMultipleChoiceFilter( # field_name='interface__name', # queryset=Interface.objects.unrestricted(), @@ -379,17 +379,31 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, return queryset.filter(address__net_mask_length=value) def filter_device(self, queryset, name, value): - try: - devices = Device.objects.prefetch_related('device_type').filter(**{'{}__in'.format(name): value}) - vc_interface_ids = [] - for device in devices: - vc_interface_ids.extend([i['id'] for i in device.vc_interfaces.values('id')]) - return queryset.filter(interface_id__in=vc_interface_ids) - except Device.DoesNotExist: + devices = Device.objects.filter(**{'{}__in'.format(name): value}) + if not devices.exists(): return queryset.none() + interface_ids = [] + for device in devices: + interface_ids.extend(device.vc_interfaces.values_list('id', flat=True)) + return queryset.filter( + assigned_object_type=ContentType.objects.get_for_model(Interface), + assigned_object_id__in=interface_ids + ) + + def filter_virtual_machine(self, queryset, name, value): + virtual_machines = VirtualMachine.objects.filter(**{'{}__in'.format(name): value}) + if not virtual_machines.exists(): + return queryset.none() + interface_ids = [] + for vm in virtual_machines: + interface_ids.extend(vm.interfaces.values_list('id', flat=True)) + return queryset.filter( + assigned_object_type=ContentType.objects.get_for_model(VMInterface), + assigned_object_id__in=interface_ids + ) def _assigned_to_interface(self, queryset, name, value): - return queryset.exclude(interface__isnull=value) + return queryset.exclude(assigned_object_id__isnull=value) class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet): diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 620638703..a66a306da 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -523,10 +523,10 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm) # class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModelForm): - interface = forms.ModelChoiceField( - queryset=Interface.objects.all(), - required=False - ) + # interface = forms.ModelChoiceField( + # queryset=Interface.objects.all(), + # required=False + # ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, @@ -598,8 +598,8 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel class Meta: model = IPAddress fields = [ - 'address', 'vrf', 'status', 'role', 'dns_name', 'description', 'interface', 'primary_for_parent', - 'nat_site', 'nat_rack', 'nat_inside', 'tenant_group', 'tenant', 'tags', + 'address', 'vrf', 'status', 'role', 'dns_name', 'description', 'primary_for_parent', 'nat_site', 'nat_rack', + 'nat_inside', 'tenant_group', 'tenant', 'tags', ] widgets = { 'status': StaticSelect2(), @@ -621,27 +621,27 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel self.fields['vrf'].empty_label = 'Global' - # Limit interface selections to those belonging to the parent device/VM - if self.instance and self.instance.interface: - self.fields['interface'].queryset = Interface.objects.filter( - device=self.instance.interface.device, virtual_machine=self.instance.interface.virtual_machine - ).prefetch_related( - 'device__primary_ip4', - 'device__primary_ip6', - 'virtual_machine__primary_ip4', - 'virtual_machine__primary_ip6', - ) # We prefetch the primary address fields to ensure cache invalidation does not balk on the save() - else: - self.fields['interface'].choices = [] - - # Initialize primary_for_parent if IP address is already assigned - if self.instance.pk and self.instance.interface is not None: - parent = self.instance.interface.parent - if ( - self.instance.address.version == 4 and parent.primary_ip4_id == self.instance.pk or - self.instance.address.version == 6 and parent.primary_ip6_id == self.instance.pk - ): - self.initial['primary_for_parent'] = True + # # Limit interface selections to those belonging to the parent device/VM + # if self.instance and self.instance.interface: + # self.fields['interface'].queryset = Interface.objects.filter( + # device=self.instance.interface.device, virtual_machine=self.instance.interface.virtual_machine + # ).prefetch_related( + # 'device__primary_ip4', + # 'device__primary_ip6', + # 'virtual_machine__primary_ip4', + # 'virtual_machine__primary_ip6', + # ) # We prefetch the primary address fields to ensure cache invalidation does not balk on the save() + # else: + # self.fields['interface'].choices = [] + # + # # Initialize primary_for_parent if IP address is already assigned + # if self.instance.pk and self.instance.interface is not None: + # parent = self.instance.interface.parent + # if ( + # self.instance.address.version == 4 and parent.primary_ip4_id == self.instance.pk or + # self.instance.address.version == 6 and parent.primary_ip6_id == self.instance.pk + # ): + # self.initial['primary_for_parent'] = True def clean(self): super().clean() @@ -664,14 +664,14 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModel else: parent.primary_ip6 = ipaddress parent.save() - elif self.cleaned_data['interface']: - parent = self.cleaned_data['interface'].parent - if ipaddress.address.version == 4 and parent.primary_ip4 == ipaddress: - parent.primary_ip4 = None - parent.save() - elif ipaddress.address.version == 6 and parent.primary_ip6 == ipaddress: - parent.primary_ip6 = None - parent.save() + # elif self.cleaned_data['interface']: + # parent = self.cleaned_data['interface'].parent + # if ipaddress.address.version == 4 and parent.primary_ip4 == ipaddress: + # parent.primary_ip4 = None + # parent.save() + # elif ipaddress.address.version == 6 and parent.primary_ip6 == ipaddress: + # parent.primary_ip6 = None + # parent.save() return ipaddress @@ -730,24 +730,24 @@ class IPAddressCSVForm(CustomFieldModelCSVForm): required=False, help_text='Functional role' ) - device = CSVModelChoiceField( - queryset=Device.objects.all(), - required=False, - to_field_name='name', - help_text='Parent device of assigned interface (if any)' - ) - virtual_machine = CSVModelChoiceField( - queryset=VirtualMachine.objects.all(), - required=False, - to_field_name='name', - help_text='Parent VM of assigned interface (if any)' - ) - interface = CSVModelChoiceField( - queryset=Interface.objects.all(), - required=False, - to_field_name='name', - help_text='Assigned interface' - ) + # device = CSVModelChoiceField( + # queryset=Device.objects.all(), + # required=False, + # to_field_name='name', + # help_text='Parent device of assigned interface (if any)' + # ) + # virtual_machine = CSVModelChoiceField( + # queryset=VirtualMachine.objects.all(), + # required=False, + # to_field_name='name', + # help_text='Parent VM of assigned interface (if any)' + # ) + # interface = CSVModelChoiceField( + # queryset=Interface.objects.all(), + # required=False, + # to_field_name='name', + # help_text='Assigned interface' + # ) is_primary = forms.BooleanField( help_text='Make this the primary IP for the assigned device', required=False @@ -760,23 +760,23 @@ class IPAddressCSVForm(CustomFieldModelCSVForm): def __init__(self, data=None, *args, **kwargs): super().__init__(data, *args, **kwargs) - if data: - - # Limit interface queryset by assigned device or virtual machine - if data.get('device'): - params = { - f"device__{self.fields['device'].to_field_name}": data.get('device') - } - elif data.get('virtual_machine'): - params = { - f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data.get('virtual_machine') - } - else: - params = { - 'device': None, - 'virtual_machine': None, - } - self.fields['interface'].queryset = self.fields['interface'].queryset.filter(**params) + # if data: + # + # # Limit interface queryset by assigned device or virtual machine + # if data.get('device'): + # params = { + # f"device__{self.fields['device'].to_field_name}": data.get('device') + # } + # elif data.get('virtual_machine'): + # params = { + # f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data.get('virtual_machine') + # } + # else: + # params = { + # 'device': None, + # 'virtual_machine': None, + # } + # self.fields['interface'].queryset = self.fields['interface'].queryset.filter(**params) def clean(self): super().clean() @@ -1197,7 +1197,7 @@ class ServiceForm(BootstrapMixin, CustomFieldModelForm): if self.instance.device: self.fields['ipaddresses'].queryset = IPAddress.objects.filter( assigned_object_type=ContentType.objects.get_for_model(Interface), - assigned_object_id__in=self.instance.device.vc_interfaces.values('id', flat=True) + assigned_object_id__in=self.instance.device.vc_interfaces.values_list('id', flat=True) ) elif self.instance.virtual_machine: self.fields['ipaddresses'].queryset = IPAddress.objects.filter( diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 640d29834..11eddb07a 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models -from django.db.models import F, Q +from django.db.models import F from django.urls import reverse from taggit.managers import TaggableManager @@ -653,7 +653,7 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): objects = IPAddressManager() csv_headers = [ - 'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface', 'is_primary', + 'address', 'vrf', 'tenant', 'status', 'role', 'assigned_object_type', 'assigned_object_id', 'is_primary', 'dns_name', 'description', ] clone_fields = [ @@ -753,17 +753,11 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): super().save(*args, **kwargs) def to_objectchange(self, action): - # Annotate the assigned Interface (if any) - try: - parent_obj = self.interface - except ObjectDoesNotExist: - parent_obj = None - return ObjectChange( changed_object=self, object_repr=str(self), action=action, - related_object=parent_obj, + related_object=self.assigned_object, object_data=serialize_object(self) ) @@ -783,9 +777,8 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): self.tenant.name if self.tenant else None, self.get_status_display(), self.get_role_display(), - self.device.identifier if self.device else None, - self.virtual_machine.name if self.virtual_machine else None, - self.interface.name if self.interface else None, + '{}.{}'.format(self.assigned_object_type.app_label, self.assigned_object_type.model) if self.assigned_object_type else None, + self.assigned_object_id, is_primary, self.dns_name, self.description, @@ -806,18 +799,6 @@ class IPAddress(ChangeLoggedModel, CustomFieldModel): self.address.prefixlen = value mask_length = property(fset=_set_mask_length) - @property - def device(self): - if self.interface: - return self.interface.device - return None - - @property - def virtual_machine(self): - if self.interface: - return self.interface.virtual_machine - return None - def get_status_class(self): return self.STATUS_CLASS_MAP.get(self.status) diff --git a/netbox/ipam/tables.py b/netbox/ipam/tables.py index 989fe0844..8f731b7ae 100644 --- a/netbox/ipam/tables.py +++ b/netbox/ipam/tables.py @@ -481,13 +481,13 @@ class IPAddressAssignTable(BaseTable): template_code=IPADDRESS_PARENT, orderable=False ) - interface = tables.Column( + assigned_object = tables.Column( orderable=False ) class Meta(BaseTable.Meta): model = IPAddress - fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'parent', 'interface', 'description') + fields = ('address', 'dns_name', 'vrf', 'status', 'role', 'tenant', 'parent', 'assigned_object', 'description') orderable = False diff --git a/netbox/ipam/tests/test_filters.py b/netbox/ipam/tests/test_filters.py index 24d0d7fa8..8382ae409 100644 --- a/netbox/ipam/tests/test_filters.py +++ b/netbox/ipam/tests/test_filters.py @@ -4,7 +4,7 @@ from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, from ipam.choices import * from ipam.filters import * from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF -from virtualization.models import Cluster, ClusterType, Interfaces as VMInterface, VirtualMachine +from virtualization.models import Cluster, ClusterType, Interface as VMInterface, VirtualMachine from tenancy.models import Tenant, TenantGroup @@ -415,16 +415,16 @@ class IPAddressTestCase(TestCase): Tenant.objects.bulk_create(tenants) ipaddresses = ( - IPAddress(address='10.0.0.1/24', tenant=None, vrf=None, interface=None, status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-a'), - IPAddress(address='10.0.0.2/24', tenant=tenants[0], vrf=vrfs[0], interface=interfaces[0], status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-b'), - IPAddress(address='10.0.0.3/24', tenant=tenants[1], vrf=vrfs[1], interface=interfaces[1], status=IPAddressStatusChoices.STATUS_RESERVED, role=IPAddressRoleChoices.ROLE_VIP, dns_name='ipaddress-c'), - IPAddress(address='10.0.0.4/24', tenant=tenants[2], vrf=vrfs[2], interface=interfaces[2], status=IPAddressStatusChoices.STATUS_DEPRECATED, role=IPAddressRoleChoices.ROLE_SECONDARY, dns_name='ipaddress-d'), - IPAddress(address='10.0.0.1/25', tenant=None, vrf=None, interface=None, status=IPAddressStatusChoices.STATUS_ACTIVE), - IPAddress(address='2001:db8::1/64', tenant=None, vrf=None, interface=None, status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-a'), - IPAddress(address='2001:db8::2/64', tenant=tenants[0], vrf=vrfs[0], interface=interfaces[3], status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-b'), - IPAddress(address='2001:db8::3/64', tenant=tenants[1], vrf=vrfs[1], interface=interfaces[4], status=IPAddressStatusChoices.STATUS_RESERVED, role=IPAddressRoleChoices.ROLE_VIP, dns_name='ipaddress-c'), - IPAddress(address='2001:db8::4/64', tenant=tenants[2], vrf=vrfs[2], interface=interfaces[5], status=IPAddressStatusChoices.STATUS_DEPRECATED, role=IPAddressRoleChoices.ROLE_SECONDARY, dns_name='ipaddress-d'), - IPAddress(address='2001:db8::1/65', tenant=None, vrf=None, interface=None, status=IPAddressStatusChoices.STATUS_ACTIVE), + IPAddress(address='10.0.0.1/24', tenant=None, vrf=None, assigned_object=None, status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-a'), + IPAddress(address='10.0.0.2/24', tenant=tenants[0], vrf=vrfs[0], assigned_object=interfaces[0], status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-b'), + IPAddress(address='10.0.0.3/24', tenant=tenants[1], vrf=vrfs[1], assigned_object=interfaces[1], status=IPAddressStatusChoices.STATUS_RESERVED, role=IPAddressRoleChoices.ROLE_VIP, dns_name='ipaddress-c'), + IPAddress(address='10.0.0.4/24', tenant=tenants[2], vrf=vrfs[2], assigned_object=interfaces[2], status=IPAddressStatusChoices.STATUS_DEPRECATED, role=IPAddressRoleChoices.ROLE_SECONDARY, dns_name='ipaddress-d'), + IPAddress(address='10.0.0.1/25', tenant=None, vrf=None, assigned_object=None, status=IPAddressStatusChoices.STATUS_ACTIVE), + IPAddress(address='2001:db8::1/64', tenant=None, vrf=None, assigned_object=None, status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-a'), + IPAddress(address='2001:db8::2/64', tenant=tenants[0], vrf=vrfs[0], assigned_object=vm_interfaces[0], status=IPAddressStatusChoices.STATUS_ACTIVE, dns_name='ipaddress-b'), + IPAddress(address='2001:db8::3/64', tenant=tenants[1], vrf=vrfs[1], assigned_object=vm_interfaces[1], status=IPAddressStatusChoices.STATUS_RESERVED, role=IPAddressRoleChoices.ROLE_VIP, dns_name='ipaddress-c'), + IPAddress(address='2001:db8::4/64', tenant=tenants[2], vrf=vrfs[2], assigned_object=vm_interfaces[2], status=IPAddressStatusChoices.STATUS_DEPRECATED, role=IPAddressRoleChoices.ROLE_SECONDARY, dns_name='ipaddress-d'), + IPAddress(address='2001:db8::1/65', tenant=None, vrf=None, assigned_object=None, status=IPAddressStatusChoices.STATUS_ACTIVE), ) IPAddress.objects.bulk_create(ipaddresses) @@ -486,12 +486,13 @@ class IPAddressTestCase(TestCase): params = {'virtual_machine': [vms[0].name, vms[1].name]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - def test_interface(self): - interfaces = Interface.objects.all()[:2] - params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - params = {'interface': ['Interface 1', 'Interface 2']} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + # TODO: Restore filtering by interface + # def test_interface(self): + # interfaces = Interface.objects.all()[:2] + # params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]} + # self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + # params = {'interface': ['Interface 1', 'Interface 2']} + # self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) def test_assigned_to_interface(self): params = {'assigned_to_interface': 'true'} diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index 06090e768..eb7f05e8f 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -236,7 +236,6 @@ class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase): 'tenant': None, 'status': IPAddressStatusChoices.STATUS_RESERVED, 'role': IPAddressRoleChoices.ROLE_ANYCAST, - 'interface': None, 'nat_inside': None, 'dns_name': 'example', 'description': 'A new IP address', diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 98fe1d73d..20355bab3 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -517,7 +517,7 @@ class PrefixIPAddressesView(ObjectView): # Find all IPAddresses belonging to this Prefix ipaddresses = prefix.get_child_ips().restrict(request.user, 'view').prefetch_related( - 'vrf', 'interface__device', 'primary_ip4_for', 'primary_ip6_for' + 'vrf', 'primary_ip4_for', 'primary_ip6_for' ) # Add available IP addresses to the table if requested @@ -593,7 +593,7 @@ class PrefixBulkDeleteView(BulkDeleteView): class IPAddressListView(ObjectListView): queryset = IPAddress.objects.prefetch_related( - 'vrf__tenant', 'tenant', 'nat_inside', 'interface__device', 'interface__virtual_machine' + 'vrf__tenant', 'tenant', 'nat_inside' ) filterset = filters.IPAddressFilterSet filterset_form = forms.IPAddressFilterForm @@ -607,49 +607,47 @@ class IPAddressView(ObjectView): ipaddress = get_object_or_404(self.queryset, pk=pk) - # Parent prefixes table - parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter( - vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip) - ).prefetch_related( - 'site', 'role' - ) - parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False) - parent_prefixes_table.exclude = ('vrf',) - - # Duplicate IPs table - duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter( - vrf=ipaddress.vrf, address=str(ipaddress.address) - ).exclude( - pk=ipaddress.pk - ).prefetch_related( - 'nat_inside', 'interface__device' - ) - # Exclude anycast IPs if this IP is anycast - if ipaddress.role == IPAddressRoleChoices.ROLE_ANYCAST: - duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST) - duplicate_ips_table = tables.IPAddressTable(list(duplicate_ips), orderable=False) - - # Related IP table - related_ips = IPAddress.objects.restrict(request.user, 'view').prefetch_related( - 'interface__device' - ).exclude( - address=str(ipaddress.address) - ).filter( - vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address) - ) - related_ips_table = tables.IPAddressTable(related_ips, orderable=False) - - paginate = { - 'paginator_class': EnhancedPaginator, - 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) - } - RequestConfig(request, paginate).configure(related_ips_table) + # # Parent prefixes table + # parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter( + # vrf=ipaddress.vrf, prefix__net_contains=str(ipaddress.address.ip) + # ).prefetch_related( + # 'site', 'role' + # ) + # parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False) + # parent_prefixes_table.exclude = ('vrf',) + # + # # Duplicate IPs table + # duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter( + # vrf=ipaddress.vrf, address=str(ipaddress.address) + # ).exclude( + # pk=ipaddress.pk + # ).prefetch_related( + # 'nat_inside' + # ) + # # Exclude anycast IPs if this IP is anycast + # if ipaddress.role == IPAddressRoleChoices.ROLE_ANYCAST: + # duplicate_ips = duplicate_ips.exclude(role=IPAddressRoleChoices.ROLE_ANYCAST) + # duplicate_ips_table = tables.IPAddressTable(list(duplicate_ips), orderable=False) + # + # # Related IP table + # related_ips = IPAddress.objects.restrict(request.user, 'view').exclude( + # address=str(ipaddress.address) + # ).filter( + # vrf=ipaddress.vrf, address__net_contained_or_equal=str(ipaddress.address) + # ) + # related_ips_table = tables.IPAddressTable(related_ips, orderable=False) + # + # paginate = { + # 'paginator_class': EnhancedPaginator, + # 'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT) + # } + # RequestConfig(request, paginate).configure(related_ips_table) return render(request, 'ipam/ipaddress.html', { 'ipaddress': ipaddress, - 'parent_prefixes_table': parent_prefixes_table, - 'duplicate_ips_table': duplicate_ips_table, - 'related_ips_table': related_ips_table, + # 'parent_prefixes_table': parent_prefixes_table, + # 'duplicate_ips_table': duplicate_ips_table, + # 'related_ips_table': related_ips_table, }) @@ -699,9 +697,7 @@ class IPAddressAssignView(ObjectView): if form.is_valid(): - addresses = self.queryset.prefetch_related( - 'vrf', 'tenant', 'interface__device', 'interface__virtual_machine' - ) + addresses = self.queryset.prefetch_related('vrf', 'tenant') # Limit to 100 results addresses = filters.IPAddressFilterSet(request.POST, addresses).qs[:100] table = tables.IPAddressAssignTable(addresses) @@ -734,7 +730,7 @@ class IPAddressBulkImportView(BulkImportView): class IPAddressBulkEditView(BulkEditView): - queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant').prefetch_related('interface__device') + queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') filterset = filters.IPAddressFilterSet table = tables.IPAddressTable form = forms.IPAddressBulkEditForm @@ -742,7 +738,7 @@ class IPAddressBulkEditView(BulkEditView): class IPAddressBulkDeleteView(BulkDeleteView): - queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant').prefetch_related('interface__device') + queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') filterset = filters.IPAddressFilterSet table = tables.IPAddressTable default_return_url = 'ipam:ipaddress_list' diff --git a/netbox/templates/ipam/ipaddress.html b/netbox/templates/ipam/ipaddress.html index 6eba1a5e6..ff83061cf 100644 --- a/netbox/templates/ipam/ipaddress.html +++ b/netbox/templates/ipam/ipaddress.html @@ -120,8 +120,8 @@