Просмотр исходного кода

Merge pull request #9695 from hagbarddenstore/issue_9686

Add Tenant Group column to tables #9686
Jeremy Stretch 3 лет назад
Родитель
Сommit
a49d3d2ddc

+ 3 - 4
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 = (

+ 3 - 3
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

+ 3 - 4
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',

+ 5 - 7
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
 
 

+ 5 - 7
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')

+ 5 - 7
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')

+ 1 - 1
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')
     )

+ 11 - 16
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, TenantColumn
 
 __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 = (

+ 3 - 4
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, TenantColumn
 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')

+ 5 - 7
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')

+ 4 - 4
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):

+ 10 - 10
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,

+ 31 - 0
netbox/tenancy/tables/columns.py

@@ -2,6 +2,8 @@ import django_tables2 as tables
 
 __all__ = (
     'TenantColumn',
+    'TenantGroupColumn',
+    'TenancyColumnsMixin',
 )
 
 
@@ -24,3 +26,32 @@ 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 %}
+        <a href="{{ record.tenant.group.get_absolute_url }}" title="{{ record.tenant.group.description }}">{{ record.tenant.group }}</a>
+    {% elif record.vrf.tenant and record.vrf.tenant.group %}
+        <a href="{{ record.vrf.tenant.group.get_absolute_url }}" title="{{ record.vrf.tenant.group.description }}">{{ record.vrf.tenant.group }}</a>*
+    {% else %}
+        &mdash;
+    {% 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
+
+
+class TenancyColumnsMixin(tables.Table):
+    tenant_group = TenantGroupColumn()
+    tenant = TenantColumn()

+ 3 - 5
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')

+ 3 - 4
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 = (