From 3c2a55a521b1a8c8a36340bf37f036f242a514a0 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 11:58:45 +0200 Subject: [PATCH 1/6] Add TenantGroupColumn to display Tenant Group on tables Works the same as the existing TenantColumn, but displats the Tenant Group of the Tenant. Views should prefetch the Tenants Group for this to be efficient in large tables. --- netbox/tenancy/tables/columns.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index bb5aba5de..aa66e8bc8 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -2,6 +2,7 @@ import django_tables2 as tables __all__ = ( 'TenantColumn', + 'TenantGroupColumn', ) @@ -24,3 +25,28 @@ class TenantColumn(tables.TemplateColumn): def value(self, value): return str(value) if value else None + + +class TenantGroupColumn(tables.TemplateColumn): + """ + Include the tenant group description. + """ + template_code = """ + {% if record.tenant and record.tenant.group %} + {{ record.tenant.group }} + {% elif record.vrf.tenant and record.vrf.tenant.group %} + {{ record.vrf.tenant.group }}* + {% else %} + — + {% endif %} + """ + + def __init__(self, *args, **kwargs): + if 'verbose_name' not in kwargs: + kwargs['verbose_name'] = 'Tenant Group' + + super().__init__(template_code=self.template_code, *args, **kwargs) + + def value(self, value): + return str(value) if value else None + From bd60d46b8285e62b05e83a36989cf39a3aaa74b4 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:08:55 +0200 Subject: [PATCH 2/6] Table mixin for Tenancy columns A mixin to add the Tenant and Tenant Group columns to a table. --- netbox/tenancy/tables/columns.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index aa66e8bc8..2d25590aa 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -3,6 +3,7 @@ import django_tables2 as tables __all__ = ( 'TenantColumn', 'TenantGroupColumn', + 'TenancyColumnsMixin', ) @@ -50,3 +51,7 @@ class TenantGroupColumn(tables.TemplateColumn): def value(self, value): return str(value) if value else None + +class TenancyColumnsMixin(tables.Table): + tenant_group = TenantGroupColumn() + tenant = TenantColumn() From e6bfde1397314950fd11dca01675abf490353cc0 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:13:48 +0200 Subject: [PATCH 3/6] Replace TenantColumn with new TenancyColumnsMixin Replaces all usages of the TenantColumn with the new TenancyColumnsMixin. This enables the user to add a column for Tenant Group on all tables which also has a column for Tenant. --- netbox/circuits/tables/circuits.py | 7 ++-- netbox/dcim/tables/cables.py | 7 ++-- netbox/dcim/tables/devices.py | 12 +++---- netbox/dcim/tables/racks.py | 12 +++---- netbox/dcim/tables/sites.py | 12 +++---- netbox/ipam/tables/ip.py | 32 ++++++++----------- netbox/ipam/tables/vlans.py | 12 +++---- netbox/ipam/tables/vrfs.py | 12 +++---- netbox/virtualization/tables/clusters.py | 8 ++--- .../virtualization/tables/virtualmachines.py | 7 ++-- 10 files changed, 50 insertions(+), 71 deletions(-) diff --git a/netbox/circuits/tables/circuits.py b/netbox/circuits/tables/circuits.py index 40f8918ae..ea4310def 100644 --- a/netbox/circuits/tables/circuits.py +++ b/netbox/circuits/tables/circuits.py @@ -2,7 +2,7 @@ import django_tables2 as tables from circuits.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .columns import CommitRateColumn __all__ = ( @@ -39,7 +39,7 @@ class CircuitTypeTable(NetBoxTable): default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug') -class CircuitTable(NetBoxTable): +class CircuitTable(TenancyColumnsMixin, NetBoxTable): cid = tables.Column( linkify=True, verbose_name='Circuit ID' @@ -48,7 +48,6 @@ class CircuitTable(NetBoxTable): linkify=True ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() termination_a = tables.TemplateColumn( template_code=CIRCUITTERMINATION_LINK, verbose_name='Side A' @@ -69,7 +68,7 @@ class CircuitTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Circuit fields = ( - 'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date', + 'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'tenant_group', 'termination_a', 'termination_z', 'install_date', 'commit_rate', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ( diff --git a/netbox/dcim/tables/cables.py b/netbox/dcim/tables/cables.py index 4b062ad48..4fd1b3266 100644 --- a/netbox/dcim/tables/cables.py +++ b/netbox/dcim/tables/cables.py @@ -3,7 +3,7 @@ from django_tables2.utils import Accessor from dcim.models import Cable from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT __all__ = ( @@ -15,7 +15,7 @@ __all__ = ( # Cables # -class CableTable(NetBoxTable): +class CableTable(TenancyColumnsMixin, NetBoxTable): termination_a_parent = tables.TemplateColumn( template_code=CABLE_TERMINATION_PARENT, accessor=Accessor('termination_a'), @@ -53,7 +53,6 @@ class CableTable(NetBoxTable): verbose_name='Termination B' ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() length = columns.TemplateColumn( template_code=CABLE_LENGTH, order_by=('_abs_length', 'length_unit') @@ -67,7 +66,7 @@ class CableTable(NetBoxTable): model = Cable fields = ( 'pk', 'id', 'label', 'termination_a_parent', 'rack_a', 'termination_a', 'termination_b_parent', 'rack_b', 'termination_b', - 'status', 'type', 'tenant', 'color', 'length', 'tags', 'created', 'last_updated', + 'status', 'type', 'tenant', 'tenant_group', 'color', 'length', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'id', 'label', 'termination_a_parent', 'termination_a', 'termination_b_parent', 'termination_b', diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 0f015b7f3..710921beb 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -6,7 +6,7 @@ from dcim.models import ( InventoryItemRole, ModuleBay, Platform, PowerOutlet, PowerPort, RearPort, VirtualChassis, ) from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import * __all__ = ( @@ -137,13 +137,12 @@ class PlatformTable(NetBoxTable): # Devices # -class DeviceTable(NetBoxTable): +class DeviceTable(TenancyColumnsMixin, NetBoxTable): name = tables.TemplateColumn( order_by=('_name',), template_code=DEVICE_LINK ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -200,7 +199,7 @@ class DeviceTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Device fields = ( - 'pk', 'id', 'name', 'status', 'tenant', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial', + 'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'primary_ip', 'airflow', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'contacts', 'tags', 'created', 'last_updated', @@ -211,12 +210,11 @@ class DeviceTable(NetBoxTable): ) -class DeviceImportTable(NetBoxTable): +class DeviceImportTable(TenancyColumnsMixin, NetBoxTable): name = tables.TemplateColumn( template_code=DEVICE_LINK ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -232,7 +230,7 @@ class DeviceImportTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Device - fields = ('id', 'name', 'status', 'tenant', 'site', 'rack', 'position', 'device_role', 'device_type') + fields = ('id', 'name', 'status', 'tenant', 'tenant_group', 'site', 'rack', 'position', 'device_role', 'device_type') empty_text = False diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index e6368cb74..5412e2297 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -3,7 +3,7 @@ from django_tables2.utils import Accessor from dcim.models import Rack, RackReservation, RackRole from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'RackTable', @@ -37,7 +37,7 @@ class RackRoleTable(NetBoxTable): # Racks # -class RackTable(NetBoxTable): +class RackTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( order_by=('_name',), linkify=True @@ -48,7 +48,6 @@ class RackTable(NetBoxTable): site = tables.Column( linkify=True ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = columns.ColoredLabelColumn() u_height = tables.TemplateColumn( @@ -87,7 +86,7 @@ class RackTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Rack fields = ( - 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', + 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'serial', 'asset_tag', 'type', 'width', 'outer_width', 'outer_depth', 'u_height', 'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'contacts', 'tags', 'created', 'last_updated', ) @@ -101,7 +100,7 @@ class RackTable(NetBoxTable): # Rack reservations # -class RackReservationTable(NetBoxTable): +class RackReservationTable(TenancyColumnsMixin, NetBoxTable): reservation = tables.Column( accessor='pk', linkify=True @@ -110,7 +109,6 @@ class RackReservationTable(NetBoxTable): accessor=Accessor('rack__site'), linkify=True ) - tenant = TenantColumn() rack = tables.Column( linkify=True ) @@ -125,7 +123,7 @@ class RackReservationTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = RackReservation fields = ( - 'pk', 'id', 'reservation', 'site', 'rack', 'unit_list', 'user', 'created', 'tenant', 'description', 'tags', + 'pk', 'id', 'reservation', 'site', 'rack', 'unit_list', 'user', 'created', 'tenant', 'tenant_group', 'description', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description') diff --git a/netbox/dcim/tables/sites.py b/netbox/dcim/tables/sites.py index fa3c73e12..1945199a3 100644 --- a/netbox/dcim/tables/sites.py +++ b/netbox/dcim/tables/sites.py @@ -2,7 +2,7 @@ import django_tables2 as tables from dcim.models import Location, Region, Site, SiteGroup from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import LOCATION_BUTTONS __all__ = ( @@ -75,7 +75,7 @@ class SiteGroupTable(NetBoxTable): # Sites # -class SiteTable(NetBoxTable): +class SiteTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) @@ -96,7 +96,6 @@ class SiteTable(NetBoxTable): url_params={'site_id': 'pk'}, verbose_name='ASN Count' ) - tenant = TenantColumn() comments = columns.MarkdownColumn() contacts = columns.ManyToManyColumn( linkify_item=True @@ -108,7 +107,7 @@ class SiteTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Site fields = ( - 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asns', 'asn_count', + 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'tenant_group', 'asns', 'asn_count', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'contacts', 'tags', 'created', 'last_updated', 'actions', ) @@ -119,14 +118,13 @@ class SiteTable(NetBoxTable): # Locations # -class LocationTable(NetBoxTable): +class LocationTable(TenancyColumnsMixin, NetBoxTable): name = columns.MPTTColumn( linkify=True ) site = tables.Column( linkify=True ) - tenant = TenantColumn() rack_count = columns.LinkedCountColumn( viewname='dcim:rack_list', url_params={'location_id': 'pk'}, @@ -150,7 +148,7 @@ class LocationTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Location fields = ( - 'pk', 'id', 'name', 'site', 'tenant', 'rack_count', 'device_count', 'description', 'slug', 'contacts', + 'pk', 'id', 'name', 'site', 'tenant', 'tenant_group', 'rack_count', 'device_count', 'description', 'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'site', 'tenant', 'rack_count', 'device_count', 'description') diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 558631585..e61d99fd8 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -4,7 +4,7 @@ from django_tables2.utils import Accessor from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'AggregateTable', @@ -99,7 +99,7 @@ class RIRTable(NetBoxTable): # ASNs # -class ASNTable(NetBoxTable): +class ASNTable(TenancyColumnsMixin, NetBoxTable): asn = tables.Column( linkify=True ) @@ -122,7 +122,6 @@ class ASNTable(NetBoxTable): linkify_item=True, verbose_name='Sites' ) - tenant = TenantColumn() tags = columns.TagColumn( url_name='ipam:asn_list' ) @@ -130,7 +129,7 @@ class ASNTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ASN fields = ( - 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'description', 'sites', 'tags', + 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'sites', 'tags', 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant') @@ -140,12 +139,11 @@ class ASNTable(NetBoxTable): # Aggregates # -class AggregateTable(NetBoxTable): +class AggregateTable(TenancyColumnsMixin, NetBoxTable): prefix = tables.Column( linkify=True, verbose_name='Aggregate' ) - tenant = TenantColumn() date_added = tables.DateColumn( format="Y-m-d", verbose_name='Added' @@ -164,7 +162,7 @@ class AggregateTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Aggregate fields = ( - 'pk', 'id', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description', 'tags', + 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', 'description', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description') @@ -225,7 +223,7 @@ class PrefixUtilizationColumn(columns.UtilizationColumn): """ -class PrefixTable(NetBoxTable): +class PrefixTable(TenancyColumnsMixin, NetBoxTable): prefix = columns.TemplateColumn( template_code=PREFIX_LINK, export_raw=True, @@ -256,7 +254,6 @@ class PrefixTable(NetBoxTable): template_code=VRF_LINK, verbose_name='VRF' ) - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -289,7 +286,7 @@ class PrefixTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Prefix fields = ( - 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', + 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', 'site', 'vlan_group', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -303,7 +300,7 @@ class PrefixTable(NetBoxTable): # # IP ranges # -class IPRangeTable(NetBoxTable): +class IPRangeTable(TenancyColumnsMixin, NetBoxTable): start_address = tables.Column( linkify=True ) @@ -317,7 +314,6 @@ class IPRangeTable(NetBoxTable): role = tables.Column( linkify=True ) - tenant = TenantColumn() utilization = columns.UtilizationColumn( accessor='utilization', orderable=False @@ -329,7 +325,7 @@ class IPRangeTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = IPRange fields = ( - 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'description', + 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description', 'utilization', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -344,7 +340,7 @@ class IPRangeTable(NetBoxTable): # IPAddresses # -class IPAddressTable(NetBoxTable): +class IPAddressTable(TenancyColumnsMixin, NetBoxTable): address = tables.TemplateColumn( template_code=IPADDRESS_LINK, verbose_name='IP Address' @@ -357,7 +353,6 @@ class IPAddressTable(NetBoxTable): default=AVAILABLE_LABEL ) role = columns.ChoiceFieldColumn() - tenant = TenantColumn() assigned_object = tables.Column( linkify=True, orderable=False, @@ -386,7 +381,7 @@ class IPAddressTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = IPAddress fields = ( - 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'assigned', 'dns_name', 'description', + 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'assigned', 'dns_name', 'description', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -414,7 +409,7 @@ class IPAddressAssignTable(NetBoxTable): orderable = False -class AssignedIPAddressesTable(NetBoxTable): +class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): """ List IP addresses assigned to an object. """ @@ -427,9 +422,8 @@ class AssignedIPAddressesTable(NetBoxTable): verbose_name='VRF' ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() class Meta(NetBoxTable.Meta): model = IPAddress - fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') + fields = ('address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description') exclude = ('id', ) diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index 4551a1c3d..4329177eb 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -5,7 +5,7 @@ from django_tables2.utils import Accessor from dcim.models import Interface from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from virtualization.models import VMInterface __all__ = ( @@ -90,7 +90,7 @@ class VLANGroupTable(NetBoxTable): # VLANs # -class VLANTable(NetBoxTable): +class VLANTable(TenancyColumnsMixin, NetBoxTable): vid = tables.TemplateColumn( template_code=VLAN_LINK, verbose_name='VID' @@ -104,7 +104,6 @@ class VLANTable(NetBoxTable): group = tables.Column( linkify=True ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn( default=AVAILABLE_LABEL ) @@ -123,7 +122,7 @@ class VLANTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN fields = ( - 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags', + 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'tenant_group', 'status', 'role', 'description', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') @@ -174,7 +173,7 @@ class VLANVirtualMachinesTable(VLANMembersTable): exclude = ('id', ) -class InterfaceVLANTable(NetBoxTable): +class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): """ List VLANs assigned to a specific Interface. """ @@ -190,7 +189,6 @@ class InterfaceVLANTable(NetBoxTable): accessor=Accessor('group__name'), verbose_name='Group' ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = tables.Column( linkify=True @@ -198,7 +196,7 @@ class InterfaceVLANTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN - fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') + fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'tenant_group', 'status', 'role', 'description') exclude = ('id', ) def __init__(self, interface, *args, **kwargs): diff --git a/netbox/ipam/tables/vrfs.py b/netbox/ipam/tables/vrfs.py index 727f402ff..69807410b 100644 --- a/netbox/ipam/tables/vrfs.py +++ b/netbox/ipam/tables/vrfs.py @@ -2,7 +2,7 @@ import django_tables2 as tables from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'RouteTargetTable', @@ -20,14 +20,13 @@ VRF_TARGETS = """ # VRFs # -class VRFTable(NetBoxTable): +class VRFTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) rd = tables.Column( verbose_name='RD' ) - tenant = TenantColumn() enforce_unique = columns.BooleanColumn( verbose_name='Unique' ) @@ -46,7 +45,7 @@ class VRFTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VRF fields = ( - 'pk', 'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', + 'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'rd', 'tenant', 'description') @@ -56,16 +55,15 @@ class VRFTable(NetBoxTable): # Route targets # -class RouteTargetTable(NetBoxTable): +class RouteTargetTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) - tenant = TenantColumn() tags = columns.TagColumn( url_name='ipam:vrf_list' ) class Meta(NetBoxTable.Meta): model = RouteTarget - fields = ('pk', 'id', 'name', 'tenant', 'description', 'tags', 'created', 'last_updated',) + fields = ('pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'tags', 'created', 'last_updated',) default_columns = ('pk', 'name', 'tenant', 'description') diff --git a/netbox/virtualization/tables/clusters.py b/netbox/virtualization/tables/clusters.py index a0c98425a..ccffe23fd 100644 --- a/netbox/virtualization/tables/clusters.py +++ b/netbox/virtualization/tables/clusters.py @@ -1,6 +1,7 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns +from tenancy.tables import TenancyColumnsMixin from virtualization.models import Cluster, ClusterGroup, ClusterType __all__ = ( @@ -56,7 +57,7 @@ class ClusterGroupTable(NetBoxTable): default_columns = ('pk', 'name', 'cluster_count', 'description') -class ClusterTable(NetBoxTable): +class ClusterTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) @@ -66,9 +67,6 @@ class ClusterTable(NetBoxTable): group = tables.Column( linkify=True ) - tenant = tables.Column( - linkify=True - ) site = tables.Column( linkify=True ) @@ -93,7 +91,7 @@ class ClusterTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Cluster fields = ( - 'pk', 'id', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'device_count', 'vm_count', 'contacts', + 'pk', 'id', 'name', 'type', 'group', 'tenant', 'tenant_group', 'site', 'comments', 'device_count', 'vm_count', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'type', 'group', 'tenant', 'site', 'device_count', 'vm_count') diff --git a/netbox/virtualization/tables/virtualmachines.py b/netbox/virtualization/tables/virtualmachines.py index 89dbdf901..8cff96227 100644 --- a/netbox/virtualization/tables/virtualmachines.py +++ b/netbox/virtualization/tables/virtualmachines.py @@ -2,7 +2,7 @@ import django_tables2 as tables from dcim.tables.devices import BaseInterfaceTable from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from virtualization.models import VirtualMachine, VMInterface __all__ = ( @@ -24,7 +24,7 @@ VMINTERFACE_BUTTONS = """ # Virtual machines # -class VirtualMachineTable(NetBoxTable): +class VirtualMachineTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( order_by=('_name',), linkify=True @@ -34,7 +34,6 @@ class VirtualMachineTable(NetBoxTable): linkify=True ) role = columns.ColoredLabelColumn() - tenant = TenantColumn() comments = columns.MarkdownColumn() primary_ip4 = tables.Column( linkify=True, @@ -56,7 +55,7 @@ class VirtualMachineTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VirtualMachine fields = ( - 'pk', 'id', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', + 'pk', 'id', 'name', 'status', 'cluster', 'role', 'tenant', 'tenant_group', 'platform', 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( From 69a22ffe5e3aefafa540f13c40e88f9c5ca0b7ec Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:38:21 +0200 Subject: [PATCH 4/6] Prefetch Tenant Group in global search Configure the prefetch to also include the Tenant Group, avoids additional database queries when the Tenant Group column is to be rendered. NOTE: If no personalisation of the global search tables should be done, this commit can be reverted. --- netbox/netbox/constants.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index 8ca0d98c1..cc04e9aa8 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -34,7 +34,7 @@ CIRCUIT_TYPES = OrderedDict( }), ('circuit', { 'queryset': Circuit.objects.prefetch_related( - 'type', 'provider', 'tenant', 'terminations__site' + 'type', 'provider', 'tenant', 'tenant__group', 'terminations__site' ), 'filterset': circuits.filtersets.CircuitFilterSet, 'table': circuits.tables.CircuitTable, @@ -53,13 +53,13 @@ CIRCUIT_TYPES = OrderedDict( DCIM_TYPES = OrderedDict( ( ('site', { - 'queryset': Site.objects.prefetch_related('region', 'tenant'), + 'queryset': Site.objects.prefetch_related('region', 'tenant', 'tenant__group'), 'filterset': dcim.filtersets.SiteFilterSet, 'table': dcim.tables.SiteTable, 'url': 'dcim:site_list', }), ('rack', { - 'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'role').annotate( + 'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'tenant__group', 'role').annotate( device_count=count_related(Device, 'rack') ), 'filterset': dcim.filtersets.RackFilterSet, @@ -100,7 +100,7 @@ DCIM_TYPES = OrderedDict( }), ('device', { 'queryset': Device.objects.prefetch_related( - 'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6', + 'device_type__manufacturer', 'device_role', 'tenant', 'tenant__group', 'site', 'rack', 'primary_ip4', 'primary_ip6', ), 'filterset': dcim.filtersets.DeviceFilterSet, 'table': dcim.tables.DeviceTable, @@ -148,7 +148,7 @@ DCIM_TYPES = OrderedDict( IPAM_TYPES = OrderedDict( ( ('vrf', { - 'queryset': VRF.objects.prefetch_related('tenant'), + 'queryset': VRF.objects.prefetch_related('tenant', 'tenant__group'), 'filterset': ipam.filtersets.VRFFilterSet, 'table': ipam.tables.VRFTable, 'url': 'ipam:vrf_list', @@ -160,25 +160,25 @@ IPAM_TYPES = OrderedDict( 'url': 'ipam:aggregate_list', }), ('prefix', { - 'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'), + 'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'tenant__group', 'vlan', 'role'), 'filterset': ipam.filtersets.PrefixFilterSet, 'table': ipam.tables.PrefixTable, 'url': 'ipam:prefix_list', }), ('ipaddress', { - 'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'), + 'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant', 'tenant__group'), 'filterset': ipam.filtersets.IPAddressFilterSet, 'table': ipam.tables.IPAddressTable, 'url': 'ipam:ipaddress_list', }), ('vlan', { - 'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'), + 'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'tenant__group', 'role'), 'filterset': ipam.filtersets.VLANFilterSet, 'table': ipam.tables.VLANTable, 'url': 'ipam:vlan_list', }), ('asn', { - 'queryset': ASN.objects.prefetch_related('rir', 'tenant'), + 'queryset': ASN.objects.prefetch_related('rir', 'tenant', 'tenant__group'), 'filterset': ipam.filtersets.ASNFilterSet, 'table': ipam.tables.ASNTable, 'url': 'ipam:asn_list', @@ -223,7 +223,7 @@ VIRTUALIZATION_TYPES = OrderedDict( }), ('virtualmachine', { 'queryset': VirtualMachine.objects.prefetch_related( - 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', + 'cluster', 'tenant', 'tenant__group', 'platform', 'primary_ip4', 'primary_ip6', ), 'filterset': virtualization.filtersets.VirtualMachineFilterSet, 'table': virtualization.tables.VirtualMachineTable, From c7ece43a1887bdc1bb3daf894c0929b9babd0505 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 17:16:12 +0200 Subject: [PATCH 5/6] Remove Tenant Group from child tables Removes the Tenant Group column from tables which aren't configurable by the user. --- netbox/ipam/tables/ip.py | 7 ++++--- netbox/ipam/tables/vlans.py | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index e61d99fd8..bec05eeff 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -4,7 +4,7 @@ from django_tables2.utils import Accessor from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenancyColumnsMixin +from tenancy.tables import TenancyColumnsMixin, TenantColumn __all__ = ( 'AggregateTable', @@ -409,7 +409,7 @@ class IPAddressAssignTable(NetBoxTable): orderable = False -class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): +class AssignedIPAddressesTable(NetBoxTable): """ List IP addresses assigned to an object. """ @@ -422,8 +422,9 @@ class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): verbose_name='VRF' ) status = columns.ChoiceFieldColumn() + tenant = TenantColumn() class Meta(NetBoxTable.Meta): model = IPAddress - fields = ('address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description') + fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') exclude = ('id', ) diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index 4329177eb..7878de507 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -5,7 +5,7 @@ from django_tables2.utils import Accessor from dcim.models import Interface from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenancyColumnsMixin +from tenancy.tables import TenancyColumnsMixin, TenantColumn from virtualization.models import VMInterface __all__ = ( @@ -173,7 +173,7 @@ class VLANVirtualMachinesTable(VLANMembersTable): exclude = ('id', ) -class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): +class InterfaceVLANTable(NetBoxTable): """ List VLANs assigned to a specific Interface. """ @@ -189,6 +189,7 @@ class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): accessor=Accessor('group__name'), verbose_name='Group' ) + tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = tables.Column( linkify=True @@ -196,7 +197,7 @@ class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN - fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'tenant_group', 'status', 'role', 'description') + fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') exclude = ('id', ) def __init__(self, interface, *args, **kwargs): From 1539769c08e200c8586de43700f8d152e7b3cc0d Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 17:17:56 +0200 Subject: [PATCH 6/6] Prefetch Tenant Group on user configurable tables Prefetch the Tenant Group in views which allows its table to be configured by the user. This decreases the amount of database queries that are required to fetch the data. --- netbox/circuits/views.py | 6 +++--- netbox/dcim/views.py | 2 +- netbox/ipam/views.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index f3b1269f9..11f211b27 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -30,7 +30,7 @@ class ProviderView(generic.ObjectView): circuits = Circuit.objects.restrict(request.user, 'view').filter( provider=instance ).prefetch_related( - 'type', 'tenant', 'terminations__site' + 'type', 'tenant', 'tenant__group', 'terminations__site' ) circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('provider',)) circuits_table.configure(request) @@ -91,7 +91,7 @@ class ProviderNetworkView(generic.ObjectView): Q(termination_a__provider_network=instance.pk) | Q(termination_z__provider_network=instance.pk) ).prefetch_related( - 'type', 'tenant', 'terminations__site' + 'type', 'tenant', 'tenant__group', 'terminations__site' ) circuits_table = tables.CircuitTable(circuits, user=request.user) circuits_table.configure(request) @@ -192,7 +192,7 @@ class CircuitTypeBulkDeleteView(generic.BulkDeleteView): class CircuitListView(generic.ObjectListView): queryset = Circuit.objects.prefetch_related( - 'provider', 'type', 'tenant', 'termination_a', 'termination_z' + 'provider', 'type', 'tenant', 'tenant__group', 'termination_a', 'termination_z' ) filterset = filtersets.CircuitFilterSet filterset_form = forms.CircuitFilterForm diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 35a1056b2..a466246f5 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -561,7 +561,7 @@ class RackRoleBulkDeleteView(generic.BulkDeleteView): class RackListView(generic.ObjectListView): queryset = Rack.objects.prefetch_related( - 'site', 'location', 'tenant', 'role', 'devices__device_type' + 'site', 'location', 'tenant', 'tenant_group', 'role', 'devices__device_type' ).annotate( device_count=count_related(Device, 'rack') ) diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 6bcdc4c64..e6b11c427 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -298,7 +298,7 @@ class AggregatePrefixesView(generic.ObjectChildrenView): def get_children(self, request, parent): return Prefix.objects.restrict(request.user, 'view').filter( prefix__net_contained_or_equal=str(parent.prefix) - ).prefetch_related('site', 'role', 'tenant', 'vlan') + ).prefetch_related('site', 'role', 'tenant', 'tenant__group', 'vlan') def prep_table_data(self, request, queryset, parent): # Determine whether to show assigned prefixes, available prefixes, or both @@ -470,7 +470,7 @@ class PrefixPrefixesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related( - 'site', 'vrf', 'vlan', 'role', 'tenant', + 'site', 'vrf', 'vlan', 'role', 'tenant', 'tenant__group' ) def prep_table_data(self, request, queryset, parent): @@ -499,7 +499,7 @@ class PrefixIPRangesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related( - 'vrf', 'role', 'tenant', + 'vrf', 'role', 'tenant', 'tenant__group', ) def get_extra_context(self, request, instance): @@ -587,7 +587,7 @@ class IPRangeIPAddressesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_ips().restrict(request.user, 'view').prefetch_related( - 'vrf', 'role', 'tenant', + 'vrf', 'role', 'tenant', 'tenant__group', ) def get_extra_context(self, request, instance):