diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 3168509ba3..021709be12 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -29,20 +29,6 @@ class ProviderListView(generic.ObjectListView): class ProviderView(generic.ObjectView): queryset = Provider.objects.all() - def get_extra_context(self, request, instance): - circuits = Circuit.objects.restrict(request.user, 'view').filter( - provider=instance - ).prefetch_related( - 'tenant__group', 'termination_a__site', 'termination_z__site', - 'termination_a__provider_network', 'termination_z__provider_network', - ) - circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('provider',)) - circuits_table.configure(request) - - return { - 'circuits_table': circuits_table, - } - @register_model_view(Provider, 'edit') class ProviderEditView(generic.ObjectEditView): @@ -93,21 +79,6 @@ class ProviderNetworkListView(generic.ObjectListView): class ProviderNetworkView(generic.ObjectView): queryset = ProviderNetwork.objects.all() - def get_extra_context(self, request, instance): - circuits = Circuit.objects.restrict(request.user, 'view').filter( - Q(termination_a__provider_network=instance.pk) | - Q(termination_z__provider_network=instance.pk) - ).prefetch_related( - 'tenant__group', 'termination_a__site', 'termination_z__site', - 'termination_a__provider_network', 'termination_z__provider_network', - ) - circuits_table = tables.CircuitTable(circuits, user=request.user) - circuits_table.configure(request) - - return { - 'circuits_table': circuits_table, - } - @register_model_view(ProviderNetwork, 'edit') class ProviderNetworkEditView(generic.ObjectEditView): @@ -156,15 +127,6 @@ class CircuitTypeListView(generic.ObjectListView): class CircuitTypeView(generic.ObjectView): queryset = CircuitType.objects.all() - def get_extra_context(self, request, instance): - circuits = Circuit.objects.restrict(request.user, 'view').filter(type=instance) - circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('type',)) - circuits_table.configure(request) - - return { - 'circuits_table': circuits_table, - } - @register_model_view(CircuitType, 'edit') class CircuitTypeEditView(generic.ObjectEditView): diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 794d58d1e2..32c06818f5 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -14,7 +14,7 @@ from circuits.models import Circuit, CircuitTermination from extras.views import ObjectConfigContextView from ipam.models import ASN, IPAddress, Prefix, Service, VLAN, VLANGroup -from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable +from ipam.tables import InterfaceVLANTable from netbox.views import generic from utilities.forms import ConfirmationForm from utilities.paginator import EnhancedPaginator, get_paginate_count @@ -210,30 +210,6 @@ class RegionListView(generic.ObjectListView): class RegionView(generic.ObjectView): queryset = Region.objects.all() - def get_extra_context(self, request, instance): - child_regions = Region.objects.add_related_count( - Region.objects.all(), - Site, - 'region', - 'site_count', - cumulative=True - ).restrict(request.user, 'view').filter( - parent__in=instance.get_descendants(include_self=True) - ) - child_regions_table = tables.RegionTable(child_regions) - child_regions_table.columns.hide('actions') - - sites = Site.objects.restrict(request.user, 'view').filter( - region=instance - ) - sites_table = tables.SiteTable(sites, user=request.user, exclude=('region',)) - sites_table.configure(request) - - return { - 'child_regions_table': child_regions_table, - 'sites_table': sites_table, - } - @register_model_view(Region, 'edit') class RegionEditView(generic.ObjectEditView): @@ -298,30 +274,6 @@ class SiteGroupListView(generic.ObjectListView): class SiteGroupView(generic.ObjectView): queryset = SiteGroup.objects.all() - def get_extra_context(self, request, instance): - child_groups = SiteGroup.objects.add_related_count( - SiteGroup.objects.all(), - Site, - 'group', - 'site_count', - cumulative=True - ).restrict(request.user, 'view').filter( - parent__in=instance.get_descendants(include_self=True) - ) - child_groups_table = tables.SiteGroupTable(child_groups) - child_groups_table.columns.hide('actions') - - sites = Site.objects.restrict(request.user, 'view').filter( - group=instance - ) - sites_table = tables.SiteTable(sites, user=request.user, exclude=('group',)) - sites_table.configure(request) - - return { - 'child_groups_table': child_groups_table, - 'sites_table': sites_table, - } - @register_model_view(SiteGroup, 'edit') class SiteGroupEditView(generic.ObjectEditView): @@ -491,22 +443,6 @@ def get_extra_context(self, request, instance): rack_count = Rack.objects.filter(location__in=location_ids).count() device_count = Device.objects.filter(location__in=location_ids).count() - child_locations = Location.objects.add_related_count( - Location.objects.add_related_count( - Location.objects.all(), - Device, - 'location', - 'device_count', - cumulative=True - ), - Rack, - 'location', - 'rack_count', - cumulative=True - ).filter(pk__in=location_ids).exclude(pk=instance.pk) - child_locations_table = tables.LocationTable(child_locations, user=request.user) - child_locations_table.configure(request) - nonracked_devices = Device.objects.filter( location=instance, rack__isnull=True, @@ -516,7 +452,6 @@ def get_extra_context(self, request, instance): return { 'rack_count': rack_count, 'device_count': device_count, - 'child_locations_table': child_locations_table, 'nonracked_devices': nonracked_devices.order_by('-pk')[:10], 'total_nonracked_devices_count': nonracked_devices.count(), } @@ -581,20 +516,6 @@ class RackRoleListView(generic.ObjectListView): class RackRoleView(generic.ObjectView): queryset = RackRole.objects.all() - def get_extra_context(self, request, instance): - racks = Rack.objects.restrict(request.user, 'view').filter(role=instance).annotate( - device_count=count_related(Device, 'rack') - ) - - racks_table = tables.RackTable(racks, user=request.user, exclude=( - 'role', 'get_utilization', 'get_power_utilization', - )) - racks_table.configure(request) - - return { - 'racks_table': racks_table, - } - @register_model_view(RackRole, 'edit') class RackRoleEditView(generic.ObjectEditView): @@ -855,8 +776,6 @@ class ManufacturerView(generic.ObjectView): def get_extra_context(self, request, instance): device_types = DeviceType.objects.restrict(request.user, 'view').filter( manufacturer=instance - ).annotate( - instance_count=count_related(Device, 'device_type') ) module_types = ModuleType.objects.restrict(request.user, 'view').filter( manufacturer=instance @@ -865,13 +784,10 @@ def get_extra_context(self, request, instance): manufacturer=instance ) - devicetypes_table = tables.DeviceTypeTable(device_types, user=request.user, exclude=('manufacturer',)) - devicetypes_table.configure(request) - return { - 'devicetypes_table': devicetypes_table, - 'inventory_item_count': inventory_items.count(), - 'module_type_count': module_types.count(), + 'devicetype_count': device_types.count(), + 'inventoryitem_count': inventory_items.count(), + 'moduletype_count': module_types.count(), } @@ -1722,19 +1638,6 @@ class DeviceRoleListView(generic.ObjectListView): class DeviceRoleView(generic.ObjectView): queryset = DeviceRole.objects.all() - def get_extra_context(self, request, instance): - devices = Device.objects.restrict(request.user, 'view').filter( - device_role=instance - ) - devices_table = tables.DeviceTable(devices, user=request.user, exclude=('device_role',)) - devices_table.configure(request) - - return { - 'devices_table': devices_table, - 'device_count': Device.objects.filter(device_role=instance).count(), - 'virtualmachine_count': VirtualMachine.objects.filter(role=instance).count(), - } - @register_model_view(DeviceRole, 'edit') class DeviceRoleEditView(generic.ObjectEditView): @@ -1793,12 +1696,13 @@ def get_extra_context(self, request, instance): devices = Device.objects.restrict(request.user, 'view').filter( platform=instance ) - devices_table = tables.DeviceTable(devices, user=request.user, exclude=('platform',)) - devices_table.configure(request) + virtual_machines = VirtualMachine.objects.restrict(request.user, 'view').filter( + platform=instance + ) return { - 'devices_table': devices_table, - 'virtualmachine_count': VirtualMachine.objects.filter(platform=instance).count() + 'device_count': devices.count(), + 'virtualmachine_count': virtual_machines.count() } @@ -2487,12 +2391,6 @@ def get_extra_context(self, request, instance): orderable=False ) - # Get assigned IP addresses - ipaddress_table = AssignedIPAddressesTable( - data=instance.ip_addresses.restrict(request.user, 'view').prefetch_related('vrf', 'tenant'), - orderable=False - ) - # Get bridge interfaces bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance) bridge_interfaces_tables = tables.InterfaceTable( @@ -2525,7 +2423,6 @@ def get_extra_context(self, request, instance): return { 'vdc_table': vdc_table, - 'ipaddress_table': ipaddress_table, 'bridge_interfaces_table': bridge_interfaces_tables, 'child_interfaces_table': child_interfaces_tables, 'vlan_table': vlan_table, @@ -3500,20 +3397,6 @@ class PowerPanelListView(generic.ObjectListView): class PowerPanelView(generic.ObjectView): queryset = PowerPanel.objects.all() - def get_extra_context(self, request, instance): - power_feeds = PowerFeed.objects.restrict(request.user).filter(power_panel=instance) - powerfeed_table = tables.PowerFeedTable( - data=power_feeds, - orderable=False - ) - if request.user.has_perm('dcim.delete_cable'): - powerfeed_table.columns.show('pk') - powerfeed_table.exclude = ['power_panel'] - - return { - 'powerfeed_table': powerfeed_table, - } - @register_model_view(PowerPanel, 'edit') class PowerPanelEditView(generic.ObjectEditView): @@ -3615,16 +3498,6 @@ class VirtualDeviceContextListView(generic.ObjectListView): class VirtualDeviceContextView(generic.ObjectView): queryset = VirtualDeviceContext.objects.all() - def get_extra_context(self, request, instance): - interfaces_table = tables.InterfaceTable(instance.interfaces, user=request.user) - interfaces_table.configure(request) - interfaces_table.columns.hide('device') - - return { - 'interfaces_table': interfaces_table, - 'interface_count': instance.interfaces.count(), - } - @register_model_view(VirtualDeviceContext, 'edit') class VirtualDeviceContextEditView(generic.ObjectEditView): diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 130014f3f1..9741be66b2 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -5,11 +5,9 @@ from django.urls import reverse from django.utils.translation import gettext as _ -from circuits.models import Provider, Circuit -from circuits.tables import ProviderTable +from circuits.models import Provider from dcim.filtersets import InterfaceFilterSet from dcim.models import Interface, Site, Device -from dcim.tables import SiteTable from netbox.views import generic from utilities.utils import count_related from utilities.views import ViewTab, register_model_view @@ -167,17 +165,6 @@ class RIRListView(generic.ObjectListView): class RIRView(generic.ObjectView): queryset = RIR.objects.all() - def get_extra_context(self, request, instance): - aggregates = Aggregate.objects.restrict(request.user, 'view').filter(rir=instance).annotate( - child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) - ) - aggregates_table = tables.AggregateTable(aggregates, user=request.user, exclude=('rir', 'utilization')) - aggregates_table.configure(request) - - return { - 'aggregates_table': aggregates_table, - } - @register_model_view(RIR, 'edit') class RIREditView(generic.ObjectEditView): @@ -232,22 +219,11 @@ class ASNView(generic.ObjectView): queryset = ASN.objects.all() def get_extra_context(self, request, instance): - # Gather assigned Sites sites = instance.sites.restrict(request.user, 'view') - sites_table = SiteTable(sites, user=request.user) - sites_table.configure(request) - - # Gather assigned Providers - providers = instance.providers.restrict(request.user, 'view').annotate( - count_circuits=count_related(Circuit, 'provider') - ) - providers_table = ProviderTable(providers, user=request.user) - providers_table.configure(request) + providers = instance.providers.restrict(request.user, 'view') return { - 'sites_table': sites_table, 'sites_count': sites.count(), - 'providers_table': providers_table, 'providers_count': providers.count(), } @@ -392,18 +368,6 @@ class RoleListView(generic.ObjectListView): class RoleView(generic.ObjectView): queryset = Role.objects.all() - def get_extra_context(self, request, instance): - prefixes = Prefix.objects.restrict(request.user, 'view').filter( - role=instance - ) - - prefixes_table = tables.PrefixTable(prefixes, user=request.user, exclude=('role', 'utilization')) - prefixes_table.configure(request) - - return { - 'prefixes_table': prefixes_table, - } - @register_model_view(Role, 'edit') class RoleEditView(generic.ObjectEditView): @@ -750,7 +714,6 @@ def get_extra_context(self, request, instance): return { 'parent_prefixes_table': parent_prefixes_table, 'duplicate_ips_table': duplicate_ips_table, - 'more_duplicate_ips': duplicate_ips.count() > 10, 'related_ips_table': related_ips_table, 'services': services, } @@ -888,17 +851,9 @@ def get_extra_context(self, request, instance): vlans_table.columns.show('pk') vlans_table.configure(request) - # Compile permissions list for rendering the object table - permissions = { - 'add': request.user.has_perm('ipam.add_vlan'), - 'change': request.user.has_perm('ipam.change_vlan'), - 'delete': request.user.has_perm('ipam.delete_vlan'), - } - return { 'vlans_count': vlans_count, 'vlans_table': vlans_table, - 'permissions': permissions, } @@ -954,11 +909,6 @@ class FHRPGroupView(generic.ObjectView): queryset = FHRPGroup.objects.all() def get_extra_context(self, request, instance): - # Get assigned IP addresses - ipaddress_table = tables.AssignedIPAddressesTable( - data=instance.ip_addresses.restrict(request.user, 'view'), - orderable=False - ) # Get assigned interfaces members_table = tables.FHRPGroupAssignmentTable( @@ -968,7 +918,6 @@ def get_extra_context(self, request, instance): members_table.columns.hide('group') return { - 'ipaddress_table': ipaddress_table, 'members_table': members_table, 'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(), } @@ -1250,10 +1199,6 @@ class L2VPNView(generic.ObjectView): queryset = L2VPN.objects.all() def get_extra_context(self, request, instance): - terminations = L2VPNTermination.objects.restrict(request.user, 'view').filter(l2vpn=instance) - terminations_table = tables.L2VPNTerminationTable(terminations, user=request.user, exclude=('l2vpn', )) - terminations_table.configure(request) - import_targets_table = tables.RouteTargetTable( instance.import_targets.prefetch_related('tenant'), orderable=False @@ -1264,7 +1209,6 @@ def get_extra_context(self, request, instance): ) return { - 'terminations_table': terminations_table, 'import_targets_table': import_targets_table, 'export_targets_table': export_targets_table, } diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py index 3a2e71084d..4060f0e482 100644 --- a/netbox/netbox/tables/tables.py +++ b/netbox/netbox/tables/tables.py @@ -4,6 +4,8 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldDoesNotExist from django.db.models.fields.related import RelatedField +from django.urls import reverse +from django.urls.exceptions import NoReverseMatch from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ from django_tables2.data import TableQuerysetData @@ -12,7 +14,7 @@ from extras.choices import CustomFieldVisibilityChoices from netbox.tables import columns from utilities.paginator import EnhancedPaginator, get_paginate_count -from utilities.utils import highlight_string, title +from utilities.utils import get_viewname, highlight_string, title __all__ = ( 'BaseTable', @@ -197,6 +199,19 @@ def __init__(self, *args, extra_columns=None, **kwargs): super().__init__(*args, extra_columns=extra_columns, **kwargs) + @property + def htmx_url(self): + """ + Return the base HTML request URL for embedded tables. + """ + if getattr(self, 'embedded', False): + viewname = get_viewname(self._meta.model, action='list') + try: + return reverse(viewname) + except NoReverseMatch: + pass + return '' + class SearchTable(tables.Table): object_type = columns.ContentTypeColumn( diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index ab3e8f100e..8dfd2c1e33 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -20,7 +20,7 @@ from utilities.error_handlers import handle_protectederror from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation from utilities.forms import BulkRenameForm, ConfirmationForm, ImportForm, restrict_form_fields -from utilities.htmx import is_htmx +from utilities.htmx import is_embedded, is_htmx from utilities.permissions import get_permission_for_model from utilities.views import GetReturnURLMixin from .base import BaseMultiObjectView @@ -161,6 +161,11 @@ def get(self, request): # If this is an HTMX request, return only the rendered table HTML if is_htmx(request): + if is_embedded(request): + table.embedded = True + # Hide selection checkboxes + if 'pk' in table.base_columns: + table.columns.hide('pk') return render(request, 'htmx/table.html', { 'table': table, }) diff --git a/netbox/templates/circuits/circuittype.html b/netbox/templates/circuits/circuittype.html index c2ab235e44..4cefecc87c 100644 --- a/netbox/templates/circuits/circuittype.html +++ b/netbox/templates/circuits/circuittype.html @@ -31,7 +31,7 @@