From 5e2967996816ed3d4e4a0dc998968f77de2dcfc6 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 17 Sep 2021 13:55:32 -0400 Subject: [PATCH 1/3] Merge 'detail' tables into primaries for each model --- netbox/dcim/tables/racks.py | 15 +---- netbox/dcim/views.py | 4 +- netbox/ipam/tables.py | 71 ++++++---------------- netbox/ipam/views.py | 44 ++++++++------ netbox/netbox/constants.py | 4 +- netbox/templates/ipam/prefix/prefixes.html | 4 +- netbox/virtualization/tables.py | 29 +++------ netbox/virtualization/views.py | 8 ++- 8 files changed, 67 insertions(+), 112 deletions(-) diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index 39a76eade..fcc3ed4d2 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -10,7 +10,6 @@ from utilities.tables import ( __all__ = ( 'RackTable', - 'RackDetailTable', 'RackReservationTable', 'RackRoleTable', ) @@ -56,17 +55,6 @@ class RackTable(BaseTable): template_code="{{ record.u_height }}U", verbose_name='Height' ) - - class Meta(BaseTable.Meta): - model = Rack - fields = ( - 'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', 'type', - 'width', 'u_height', - ) - default_columns = ('pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'u_height') - - -class RackDetailTable(RackTable): comments = MarkdownColumn() device_count = LinkedCountColumn( viewname='dcim:device_list', @@ -85,7 +73,8 @@ class RackDetailTable(RackTable): url_name='dcim:rack_list' ) - class Meta(RackTable.Meta): + class Meta(BaseTable.Meta): + model = Rack fields = ( 'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'tags', diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 4305d3c63..fbdd30a3d 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -455,6 +455,8 @@ class RackRoleView(generic.ObjectView): racks_table = tables.RackTable(racks) racks_table.columns.hide('role') + racks_table.columns.hide('get_utilization') + racks_table.columns.hide('get_power_utilization') paginate_table(racks_table, request) return { @@ -505,7 +507,7 @@ class RackListView(generic.ObjectListView): ) filterset = filtersets.RackFilterSet filterset_form = forms.RackFilterForm - table = tables.RackDetailTable + table = tables.RackTable class RackElevationListView(generic.ObjectListView): diff --git a/netbox/ipam/tables.py b/netbox/ipam/tables.py index 5afb6a9c9..a39df2601 100644 --- a/netbox/ipam/tables.py +++ b/netbox/ipam/tables.py @@ -215,13 +215,6 @@ class AggregateTable(BaseTable): format="Y-m-d", verbose_name='Added' ) - - class Meta(BaseTable.Meta): - model = Aggregate - fields = ('pk', 'prefix', 'rir', 'tenant', 'date_added', 'description') - - -class AggregateDetailTable(AggregateTable): child_count = tables.Column( verbose_name='Prefixes' ) @@ -233,7 +226,8 @@ class AggregateDetailTable(AggregateTable): url_name='ipam:aggregate_list' ) - class Meta(AggregateTable.Meta): + class Meta(BaseTable.Meta): + model = Aggregate fields = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description', 'tags') default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description') @@ -332,20 +326,6 @@ class PrefixTable(BaseTable): mark_utilized = BooleanColumn( verbose_name='Marked Utilized' ) - - class Meta(BaseTable.Meta): - model = Prefix - fields = ( - 'pk', 'prefix', 'prefix_flat', 'status', 'depth', 'children', 'vrf', 'tenant', 'site', 'vlan', 'role', - 'is_pool', 'mark_utilized', 'description', - ) - default_columns = ('pk', 'prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'description') - row_attrs = { - 'class': lambda record: 'success' if not record.pk else '', - } - - -class PrefixDetailTable(PrefixTable): utilization = PrefixUtilizationColumn( accessor='get_utilization', orderable=False @@ -354,7 +334,8 @@ class PrefixDetailTable(PrefixTable): url_name='ipam:prefix_list' ) - class Meta(PrefixTable.Meta): + class Meta(BaseTable.Meta): + model = Prefix fields = ( 'pk', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', @@ -362,6 +343,9 @@ class PrefixDetailTable(PrefixTable): default_columns = ( 'pk', 'prefix', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description', ) + row_attrs = { + 'class': lambda record: 'success' if not record.pk else '', + } # @@ -427,25 +411,11 @@ class IPAddressTable(BaseTable): orderable=False, verbose_name='Device/VM' ) - - class Meta(BaseTable.Meta): - model = IPAddress - fields = ( - 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned_object', 'assigned_object_parent', 'dns_name', - 'description', - ) - row_attrs = { - 'class': lambda record: 'success' if not isinstance(record, IPAddress) else '', - } - - -class IPAddressDetailTable(IPAddressTable): nat_inside = tables.Column( linkify=True, orderable=False, verbose_name='NAT (Inside)' ) - tenant = TenantColumn() assigned = BooleanColumn( accessor='assigned_object_id', verbose_name='Assigned' @@ -454,14 +424,18 @@ class IPAddressDetailTable(IPAddressTable): url_name='ipam:ipaddress_list' ) - class Meta(IPAddressTable.Meta): + class Meta(BaseTable.Meta): + model = IPAddress fields = ( - 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'assigned', 'dns_name', - 'description', 'tags', + 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'assigned', 'dns_name', 'description', + 'tags', ) default_columns = ( 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned', 'dns_name', 'description', ) + row_attrs = { + 'class': lambda record: 'success' if not isinstance(record, IPAddress) else '', + } class IPAddressAssignTable(BaseTable): @@ -554,29 +528,22 @@ class VLANTable(BaseTable): role = tables.TemplateColumn( template_code=VLAN_ROLE_LINK ) - - class Meta(BaseTable.Meta): - model = VLAN - fields = ('pk', 'vid', 'name', 'site', 'group', 'tenant', 'status', 'role', 'description') - row_attrs = { - 'class': lambda record: 'success' if not isinstance(record, VLAN) else '', - } - - -class VLANDetailTable(VLANTable): prefixes = tables.TemplateColumn( template_code=VLAN_PREFIXES, orderable=False, verbose_name='Prefixes' ) - tenant = TenantColumn() tags = TagColumn( url_name='ipam:vlan_list' ) - class Meta(VLANTable.Meta): + class Meta(BaseTable.Meta): + model = VLAN fields = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags') default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') + row_attrs = { + 'class': lambda record: 'success' if not isinstance(record, VLAN) else '', + } class VLANMembersTable(BaseTable): diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 64ca5bc43..6d49cd24f 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -158,6 +158,7 @@ class RIRView(generic.ObjectView): aggregates_table = tables.AggregateTable(aggregates) aggregates_table.columns.hide('rir') + aggregates_table.columns.hide('utilization') paginate_table(aggregates_table, request) return { @@ -207,7 +208,7 @@ class AggregateListView(generic.ObjectListView): ) filterset = filtersets.AggregateFilterSet filterset_form = forms.AggregateFilterForm - table = tables.AggregateDetailTable + table = tables.AggregateTable class AggregateView(generic.ObjectView): @@ -227,7 +228,7 @@ class AggregateView(generic.ObjectView): if request.GET.get('show_available', 'true') == 'true': child_prefixes = add_available_prefixes(instance.prefix, child_prefixes) - prefix_table = tables.PrefixDetailTable(child_prefixes) + prefix_table = tables.PrefixTable(child_prefixes, exclude=('utilization',)) if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): prefix_table.columns.show('pk') paginate_table(prefix_table, request) @@ -296,8 +297,7 @@ class RoleView(generic.ObjectView): role=instance ) - prefixes_table = tables.PrefixTable(prefixes) - prefixes_table.columns.hide('role') + prefixes_table = tables.PrefixTable(prefixes, exclude=('role', 'utilization')) paginate_table(prefixes_table, request) return { @@ -340,7 +340,7 @@ class PrefixListView(generic.ObjectListView): queryset = Prefix.objects.all() filterset = filtersets.PrefixFilterSet filterset_form = forms.PrefixFilterForm - table = tables.PrefixDetailTable + table = tables.PrefixTable template_name = 'ipam/prefix_list.html' @@ -363,8 +363,11 @@ class PrefixView(generic.ObjectView): ).prefetch_related( 'site', 'role' ) - parent_prefix_table = tables.PrefixTable(list(parent_prefixes), orderable=False) - parent_prefix_table.exclude = ('vrf',) + parent_prefix_table = tables.PrefixTable( + list(parent_prefixes), + exclude=('vrf', 'utilization'), + orderable=False + ) # Duplicate prefixes table duplicate_prefixes = Prefix.objects.restrict(request.user, 'view').filter( @@ -374,8 +377,11 @@ class PrefixView(generic.ObjectView): ).prefetch_related( 'site', 'role' ) - duplicate_prefix_table = tables.PrefixTable(list(duplicate_prefixes), orderable=False) - duplicate_prefix_table.exclude = ('vrf',) + duplicate_prefix_table = tables.PrefixTable( + list(duplicate_prefixes), + exclude=('vrf', 'utilization'), + orderable=False + ) return { 'aggregate': aggregate, @@ -398,7 +404,7 @@ class PrefixPrefixesView(generic.ObjectView): if child_prefixes and request.GET.get('show_available', 'true') == 'true': child_prefixes = add_available_prefixes(instance.prefix, child_prefixes) - table = tables.PrefixDetailTable(child_prefixes, user=request.user) + table = tables.PrefixTable(child_prefixes, user=request.user, exclude=('utilization',)) if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'): table.columns.show('pk') paginate_table(table, request) @@ -601,7 +607,7 @@ class IPAddressListView(generic.ObjectListView): queryset = IPAddress.objects.all() filterset = filtersets.IPAddressFilterSet filterset_form = forms.IPAddressFilterForm - table = tables.IPAddressDetailTable + table = tables.IPAddressTable class IPAddressView(generic.ObjectView): @@ -615,8 +621,11 @@ class IPAddressView(generic.ObjectView): ).prefetch_related( 'site', 'role' ) - parent_prefixes_table = tables.PrefixTable(list(parent_prefixes), orderable=False) - parent_prefixes_table.exclude = ('vrf',) + parent_prefixes_table = tables.PrefixTable( + list(parent_prefixes), + exclude=('vrf', 'utilization'), + orderable=False + ) # Duplicate IPs table duplicate_ips = IPAddress.objects.restrict(request.user, 'view').filter( @@ -767,11 +776,9 @@ class VLANGroupView(generic.ObjectView): vlans_count = vlans.count() vlans = add_available_vlans(vlans, vlan_group=instance) - vlans_table = tables.VLANDetailTable(vlans) + vlans_table = tables.VLANTable(vlans, exclude=('site', 'group', 'prefixes')) if request.user.has_perm('ipam.change_vlan') or request.user.has_perm('ipam.delete_vlan'): vlans_table.columns.show('pk') - vlans_table.columns.hide('site') - vlans_table.columns.hide('group') paginate_table(vlans_table, request) # Compile permissions list for rendering the object table @@ -828,7 +835,7 @@ class VLANListView(generic.ObjectListView): queryset = VLAN.objects.all() filterset = filtersets.VLANFilterSet filterset_form = forms.VLANFilterForm - table = tables.VLANDetailTable + table = tables.VLANTable class VLANView(generic.ObjectView): @@ -838,8 +845,7 @@ class VLANView(generic.ObjectView): prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related( 'vrf', 'site', 'role' ) - prefix_table = tables.PrefixTable(list(prefixes), orderable=False) - prefix_table.exclude = ('vlan',) + prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False) return { 'prefix_table': prefix_table, diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index 31e56fb1f..ec6daa021 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -21,7 +21,7 @@ from tenancy.tables import TenantTable from utilities.utils import count_related from virtualization.filtersets import ClusterFilterSet, VirtualMachineFilterSet from virtualization.models import Cluster, VirtualMachine -from virtualization.tables import ClusterTable, VirtualMachineDetailTable +from virtualization.tables import ClusterTable, VirtualMachineTable SEARCH_MAX_RESULTS = 15 SEARCH_TYPES = OrderedDict(( @@ -130,7 +130,7 @@ SEARCH_TYPES = OrderedDict(( 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', ), 'filterset': VirtualMachineFilterSet, - 'table': VirtualMachineDetailTable, + 'table': VirtualMachineTable, 'url': 'virtualization:virtualmachine_list', }), # IPAM diff --git a/netbox/templates/ipam/prefix/prefixes.html b/netbox/templates/ipam/prefix/prefixes.html index e6c109a39..d10ca79db 100644 --- a/netbox/templates/ipam/prefix/prefixes.html +++ b/netbox/templates/ipam/prefix/prefixes.html @@ -15,9 +15,9 @@ {% block content %}
- {% include 'inc/table_controls.html' with table_modal="PrefixDetailTable_config" %} + {% include 'inc/table_controls.html' with table_modal="PrefixTable_config" %} {% include 'utilities/obj_table.html' with heading='Child Prefixes' bulk_edit_url='ipam:prefix_bulk_edit' bulk_delete_url='ipam:prefix_bulk_delete' parent=prefix %}
- {% table_config_form table table_name="PrefixDetailTable" %} + {% table_config_form table table_name="PrefixTable" %} {% endblock %} diff --git a/netbox/virtualization/tables.py b/netbox/virtualization/tables.py index c6d42d3c1..b0e922e71 100644 --- a/netbox/virtualization/tables.py +++ b/netbox/virtualization/tables.py @@ -12,12 +12,13 @@ __all__ = ( 'ClusterTable', 'ClusterGroupTable', 'ClusterTypeTable', - 'VirtualMachineDetailTable', 'VirtualMachineTable', 'VirtualMachineVMInterfaceTable', 'VMInterfaceTable', ) +PRIMARY_IP_ORDERING = ('primary_ip4', 'primary_ip6') if settings.PREFER_IPV4 else ('primary_ip6', 'primary_ip4') + VMINTERFACE_BUTTONS = """ {% if perms.ipam.add_ipaddress %} @@ -118,13 +119,7 @@ class VirtualMachineTable(BaseTable): ) role = ColoredLabelColumn() tenant = TenantColumn() - - class Meta(BaseTable.Meta): - model = VirtualMachine - fields = ('pk', 'name', 'status', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk') - - -class VirtualMachineDetailTable(VirtualMachineTable): + comments = MarkdownColumn() primary_ip4 = tables.Column( linkify=True, verbose_name='IPv4 Address' @@ -133,19 +128,11 @@ class VirtualMachineDetailTable(VirtualMachineTable): linkify=True, verbose_name='IPv6 Address' ) - if settings.PREFER_IPV4: - primary_ip = tables.Column( - linkify=True, - order_by=('primary_ip4', 'primary_ip6'), - verbose_name='IP Address' - ) - else: - primary_ip = tables.Column( - linkify=True, - order_by=('primary_ip6', 'primary_ip4'), - verbose_name='IP Address' - ) - comments = MarkdownColumn() + primary_ip = tables.Column( + linkify=True, + order_by=PRIMARY_IP_ORDERING, + verbose_name='IP Address' + ) tags = TagColumn( url_name='virtualization:virtualmachine_list' ) diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 115ca0a29..8315ba0a6 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -171,7 +171,11 @@ class ClusterVirtualMachinesView(generic.ObjectView): def get_extra_context(self, request, instance): virtualmachines = VirtualMachine.objects.restrict(request.user, 'view').filter(cluster=instance) - virtualmachines_table = tables.VirtualMachineTable(virtualmachines, orderable=False) + virtualmachines_table = tables.VirtualMachineTable( + virtualmachines, + exclude=('cluster',), + orderable=False + ) return { 'virtualmachines_table': virtualmachines_table, @@ -315,7 +319,7 @@ class VirtualMachineListView(generic.ObjectListView): queryset = VirtualMachine.objects.all() filterset = filtersets.VirtualMachineFilterSet filterset_form = forms.VirtualMachineFilterForm - table = tables.VirtualMachineDetailTable + table = tables.VirtualMachineTable template_name = 'virtualization/virtualmachine_list.html' From 9cb29f48a0d00d63e39177ff60c65525b2cdfe6a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 17 Sep 2021 14:25:02 -0400 Subject: [PATCH 2/3] Use exclude() when instantiating tables to omit columns --- netbox/circuits/views.py | 15 +++------------ netbox/dcim/views.py | 24 +++++++----------------- netbox/ipam/views.py | 5 +---- netbox/tenancy/views.py | 4 +--- netbox/virtualization/views.py | 10 +++------- 5 files changed, 15 insertions(+), 43 deletions(-) diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 3460d4626..b549b3a01 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -34,9 +34,7 @@ class ProviderView(generic.ObjectView): ).prefetch_related( 'type', 'tenant', 'terminations__site' ) - - circuits_table = tables.CircuitTable(circuits) - circuits_table.columns.hide('provider') + circuits_table = tables.CircuitTable(circuits, exclude=('provider',)) paginate_table(circuits_table, request) return { @@ -97,10 +95,7 @@ class ProviderNetworkView(generic.ObjectView): ).prefetch_related( 'type', 'tenant', 'terminations__site' ) - circuits_table = tables.CircuitTable(circuits) - circuits_table.columns.hide('termination_a') - circuits_table.columns.hide('termination_z') paginate_table(circuits_table, request) return { @@ -153,12 +148,8 @@ 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) - circuits_table.columns.hide('type') + circuits = Circuit.objects.restrict(request.user, 'view').filter(type=instance) + circuits_table = tables.CircuitTable(circuits, exclude=('type',)) paginate_table(circuits_table, request) return { diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index fbdd30a3d..63f2be5c8 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -131,8 +131,7 @@ class RegionView(generic.ObjectView): sites = Site.objects.restrict(request.user, 'view').filter( region=instance ) - sites_table = tables.SiteTable(sites) - sites_table.columns.hide('region') + sites_table = tables.SiteTable(sites, exclude=('region',)) paginate_table(sites_table, request) return { @@ -216,8 +215,7 @@ class SiteGroupView(generic.ObjectView): sites = Site.objects.restrict(request.user, 'view').filter( group=instance ) - sites_table = tables.SiteTable(sites) - sites_table.columns.hide('group') + sites_table = tables.SiteTable(sites, exclude=('group',)) paginate_table(sites_table, request) return { @@ -453,10 +451,7 @@ class RackRoleView(generic.ObjectView): role=instance ) - racks_table = tables.RackTable(racks) - racks_table.columns.hide('role') - racks_table.columns.hide('get_utilization') - racks_table.columns.hide('get_power_utilization') + racks_table = tables.RackTable(racks, exclude=('role', 'get_utilization', 'get_power_utilization')) paginate_table(racks_table, request) return { @@ -706,8 +701,7 @@ class ManufacturerView(generic.ObjectView): manufacturer=instance ) - devicetypes_table = tables.DeviceTypeTable(devicetypes) - devicetypes_table.columns.hide('manufacturer') + devicetypes_table = tables.DeviceTypeTable(devicetypes, exclude=('manufacturer',)) paginate_table(devicetypes_table, request) return { @@ -1167,9 +1161,7 @@ class DeviceRoleView(generic.ObjectView): devices = Device.objects.restrict(request.user, 'view').filter( device_role=instance ) - - devices_table = tables.DeviceTable(devices) - devices_table.columns.hide('device_role') + devices_table = tables.DeviceTable(devices, exclude=('device_role',)) paginate_table(devices_table, request) return { @@ -1233,9 +1225,7 @@ class PlatformView(generic.ObjectView): devices = Device.objects.restrict(request.user, 'view').filter( platform=instance ) - - devices_table = tables.DeviceTable(devices) - devices_table.columns.hide('platform') + devices_table = tables.DeviceTable(devices, exclude=('platform',)) paginate_table(devices_table, request) return { @@ -1880,9 +1870,9 @@ class InterfaceView(generic.ObjectView): child_interfaces = Interface.objects.restrict(request.user, 'view').filter(parent=instance) child_interfaces_tables = tables.InterfaceTable( child_interfaces, + exclude=('device', 'parent'), orderable=False ) - child_interfaces_tables.columns.hide('device') # Get assigned VLANs and annotate whether each is tagged or untagged vlans = [] diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 6d49cd24f..015d47065 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -155,10 +155,7 @@ class RIRView(generic.ObjectView): aggregates = Aggregate.objects.restrict(request.user, 'view').filter( rir=instance ) - - aggregates_table = tables.AggregateTable(aggregates) - aggregates_table.columns.hide('rir') - aggregates_table.columns.hide('utilization') + aggregates_table = tables.AggregateTable(aggregates, exclude=('rir', 'utilization')) paginate_table(aggregates_table, request) return { diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 22d669a0d..0b28a62d2 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -32,9 +32,7 @@ class TenantGroupView(generic.ObjectView): tenants = Tenant.objects.restrict(request.user, 'view').filter( group=instance ) - - tenants_table = tables.TenantTable(tenants) - tenants_table.columns.hide('group') + tenants_table = tables.TenantTable(tenants, exclude=('group',)) paginate_table(tenants_table, request) return { diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 8315ba0a6..a8b2b8f1f 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -39,9 +39,7 @@ class ClusterTypeView(generic.ObjectView): device_count=count_related(Device, 'cluster'), vm_count=count_related(VirtualMachine, 'cluster') ) - - clusters_table = tables.ClusterTable(clusters) - clusters_table.columns.hide('type') + clusters_table = tables.ClusterTable(clusters, exclude=('type',)) paginate_table(clusters_table, request) return { @@ -103,9 +101,7 @@ class ClusterGroupView(generic.ObjectView): device_count=count_related(Device, 'cluster'), vm_count=count_related(VirtualMachine, 'cluster') ) - - clusters_table = tables.ClusterTable(clusters) - clusters_table.columns.hide('group') + clusters_table = tables.ClusterTable(clusters, exclude=('group',)) paginate_table(clusters_table, request) return { @@ -434,9 +430,9 @@ class VMInterfaceView(generic.ObjectView): child_interfaces = VMInterface.objects.restrict(request.user, 'view').filter(parent=instance) child_interfaces_tables = tables.VMInterfaceTable( child_interfaces, + exclude=('virtual_machine',), orderable=False ) - child_interfaces_tables.columns.hide('virtual_machine') # Get assigned VLANs and annotate whether each is tagged or untagged vlans = [] From 7b3f6f1c673fe602530c7727c94ffbf3de0cdb08 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 17 Sep 2021 15:37:19 -0400 Subject: [PATCH 3/3] Clean up table classes --- netbox/circuits/tables.py | 8 + netbox/dcim/tables/devices.py | 1 + netbox/extras/tables.py | 13 ++ netbox/ipam/tables/__init__.py | 4 + netbox/ipam/{tables.py => tables/ip.py} | 288 ++---------------------- netbox/ipam/tables/services.py | 35 +++ netbox/ipam/tables/vlans.py | 203 +++++++++++++++++ netbox/ipam/tables/vrfs.py | 74 ++++++ netbox/tenancy/tables.py | 6 + 9 files changed, 357 insertions(+), 275 deletions(-) create mode 100644 netbox/ipam/tables/__init__.py rename netbox/ipam/{tables.py => tables/ip.py} (59%) create mode 100644 netbox/ipam/tables/services.py create mode 100644 netbox/ipam/tables/vlans.py create mode 100644 netbox/ipam/tables/vrfs.py diff --git a/netbox/circuits/tables.py b/netbox/circuits/tables.py index c3e616d8a..2e31237b6 100644 --- a/netbox/circuits/tables.py +++ b/netbox/circuits/tables.py @@ -6,6 +6,14 @@ from utilities.tables import BaseTable, ButtonsColumn, ChoiceFieldColumn, Markdo from .models import * +__all__ = ( + 'CircuitTable', + 'CircuitTypeTable', + 'ProviderTable', + 'ProviderNetworkTable', +) + + CIRCUITTERMINATION_LINK = """ {% if value.site %} {{ value.site }} diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index dda0af2b4..306b29b09 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -18,6 +18,7 @@ from .template_code import ( ) __all__ = ( + 'BaseInterfaceTable', 'ConsolePortTable', 'ConsoleServerPortTable', 'DeviceBayTable', diff --git a/netbox/extras/tables.py b/netbox/extras/tables.py index c556e312f..20a6ffd8a 100644 --- a/netbox/extras/tables.py +++ b/netbox/extras/tables.py @@ -7,6 +7,19 @@ from utilities.tables import ( ) from .models import * +__all__ = ( + 'ConfigContextTable', + 'CustomFieldTable', + 'CustomLinkTable', + 'ExportTemplateTable', + 'JournalEntryTable', + 'ObjectChangeTable', + 'ObjectJournalTable', + 'TaggedItemTable', + 'TagTable', + 'WebhookTable', +) + CONFIGCONTEXT_ACTIONS = """ {% if perms.extras.change_configcontext %} diff --git a/netbox/ipam/tables/__init__.py b/netbox/ipam/tables/__init__.py new file mode 100644 index 000000000..a280eac1b --- /dev/null +++ b/netbox/ipam/tables/__init__.py @@ -0,0 +1,4 @@ +from .ip import * +from .services import * +from .vlans import * +from .vrfs import * diff --git a/netbox/ipam/tables.py b/netbox/ipam/tables/ip.py similarity index 59% rename from netbox/ipam/tables.py rename to netbox/ipam/tables/ip.py index a39df2601..2e59a681c 100644 --- a/netbox/ipam/tables.py +++ b/netbox/ipam/tables/ip.py @@ -2,14 +2,23 @@ import django_tables2 as tables from django.utils.safestring import mark_safe from django_tables2.utils import Accessor -from dcim.models import Interface from tenancy.tables import TenantColumn from utilities.tables import ( - BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn, + BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, LinkedCountColumn, TagColumn, ToggleColumn, UtilizationColumn, ) -from virtualization.models import VMInterface -from .models import * +from ipam.models import * + +__all__ = ( + 'AggregateTable', + 'InterfaceIPAddressTable', + 'IPAddressAssignTable', + 'IPAddressTable', + 'IPRangeTable', + 'PrefixTable', + 'RIRTable', + 'RoleTable', +) AVAILABLE_LABEL = mark_safe('Available') @@ -66,114 +75,6 @@ VRF_LINK = """ {% endif %} """ -VRF_TARGETS = """ -{% for rt in value.all %} - {{ rt }}{% if not forloop.last %}
{% endif %} -{% empty %} - — -{% endfor %} -""" - -VLAN_LINK = """ -{% if record.pk %} - {{ record.vid }} -{% elif perms.ipam.add_vlan %} - {{ record.available }} VLAN{{ record.available|pluralize }} available -{% else %} - {{ record.available }} VLAN{{ record.available|pluralize }} available -{% endif %} -""" - -VLAN_PREFIXES = """ -{% for prefix in record.prefixes.all %} - {{ prefix }}{% if not forloop.last %}
{% endif %} -{% empty %} - — -{% endfor %} -""" - -VLAN_ROLE_LINK = """ -{% if record.role %} - {{ record.role }} -{% else %} - — -{% endif %} -""" - -VLANGROUP_ADD_VLAN = """ -{% with next_vid=record.get_next_available_vid %} - {% if next_vid and perms.ipam.add_vlan %} - - - - {% endif %} -{% endwith %} -""" - -VLAN_MEMBER_TAGGED = """ -{% if record.untagged_vlan_id == object.pk %} - -{% else %} - -{% endif %} -""" - - -# -# VRFs -# - -class VRFTable(BaseTable): - pk = ToggleColumn() - name = tables.Column( - linkify=True - ) - rd = tables.Column( - verbose_name='RD' - ) - tenant = TenantColumn() - enforce_unique = BooleanColumn( - verbose_name='Unique' - ) - import_targets = tables.TemplateColumn( - template_code=VRF_TARGETS, - orderable=False - ) - export_targets = tables.TemplateColumn( - template_code=VRF_TARGETS, - orderable=False - ) - tags = TagColumn( - url_name='ipam:vrf_list' - ) - - class Meta(BaseTable.Meta): - model = VRF - fields = ( - 'pk', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tags', - ) - default_columns = ('pk', 'name', 'rd', 'tenant', 'description') - - -# -# Route targets -# - -class RouteTargetTable(BaseTable): - pk = ToggleColumn() - name = tables.Column( - linkify=True - ) - tenant = TenantColumn() - tags = TagColumn( - url_name='ipam:vrf_list' - ) - - class Meta(BaseTable.Meta): - model = RouteTarget - fields = ('pk', 'name', 'tenant', 'description', 'tags') - default_columns = ('pk', 'name', 'tenant', 'description') - # # RIRs @@ -475,166 +376,3 @@ class InterfaceIPAddressTable(BaseTable): class Meta(BaseTable.Meta): model = IPAddress fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') - - -# -# VLAN groups -# - -class VLANGroupTable(BaseTable): - pk = ToggleColumn() - name = tables.Column(linkify=True) - scope_type = ContentTypeColumn() - scope = tables.Column( - linkify=True, - orderable=False - ) - vlan_count = LinkedCountColumn( - viewname='ipam:vlan_list', - url_params={'group_id': 'pk'}, - verbose_name='VLANs' - ) - actions = ButtonsColumn( - model=VLANGroup, - prepend_template=VLANGROUP_ADD_VLAN - ) - - class Meta(BaseTable.Meta): - model = VLANGroup - fields = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'slug', 'description', 'actions') - default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'description', 'actions') - - -# -# VLANs -# - -class VLANTable(BaseTable): - pk = ToggleColumn() - vid = tables.TemplateColumn( - template_code=VLAN_LINK, - verbose_name='ID' - ) - site = tables.Column( - linkify=True - ) - group = tables.Column( - linkify=True - ) - tenant = TenantColumn() - status = ChoiceFieldColumn( - default=AVAILABLE_LABEL - ) - role = tables.TemplateColumn( - template_code=VLAN_ROLE_LINK - ) - prefixes = tables.TemplateColumn( - template_code=VLAN_PREFIXES, - orderable=False, - verbose_name='Prefixes' - ) - tags = TagColumn( - url_name='ipam:vlan_list' - ) - - class Meta(BaseTable.Meta): - model = VLAN - fields = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags') - default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') - row_attrs = { - 'class': lambda record: 'success' if not isinstance(record, VLAN) else '', - } - - -class VLANMembersTable(BaseTable): - """ - Base table for Interface and VMInterface assignments - """ - name = tables.Column( - linkify=True, - verbose_name='Interface' - ) - tagged = tables.TemplateColumn( - template_code=VLAN_MEMBER_TAGGED, - orderable=False - ) - - -class VLANDevicesTable(VLANMembersTable): - device = tables.Column( - linkify=True - ) - actions = ButtonsColumn(Interface, buttons=['edit']) - - class Meta(BaseTable.Meta): - model = Interface - fields = ('device', 'name', 'tagged', 'actions') - - -class VLANVirtualMachinesTable(VLANMembersTable): - virtual_machine = tables.Column( - linkify=True - ) - actions = ButtonsColumn(VMInterface, buttons=['edit']) - - class Meta(BaseTable.Meta): - model = VMInterface - fields = ('virtual_machine', 'name', 'tagged', 'actions') - - -class InterfaceVLANTable(BaseTable): - """ - List VLANs assigned to a specific Interface. - """ - vid = tables.Column( - linkify=True, - verbose_name='ID' - ) - tagged = BooleanColumn() - site = tables.Column( - linkify=True - ) - group = tables.Column( - accessor=Accessor('group__name'), - verbose_name='Group' - ) - tenant = TenantColumn() - status = ChoiceFieldColumn() - role = tables.TemplateColumn( - template_code=VLAN_ROLE_LINK - ) - - class Meta(BaseTable.Meta): - model = VLAN - fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') - - def __init__(self, interface, *args, **kwargs): - self.interface = interface - super().__init__(*args, **kwargs) - - -# -# Services -# - -class ServiceTable(BaseTable): - pk = ToggleColumn() - name = tables.Column( - linkify=True - ) - parent = tables.Column( - linkify=True, - order_by=('device', 'virtual_machine') - ) - ports = tables.TemplateColumn( - template_code='{{ record.port_list }}', - verbose_name='Ports' - ) - tags = TagColumn( - url_name='ipam:service_list' - ) - - class Meta(BaseTable.Meta): - model = Service - fields = ('pk', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'tags') - default_columns = ('pk', 'name', 'parent', 'protocol', 'ports', 'description') diff --git a/netbox/ipam/tables/services.py b/netbox/ipam/tables/services.py new file mode 100644 index 000000000..58c8ea49e --- /dev/null +++ b/netbox/ipam/tables/services.py @@ -0,0 +1,35 @@ +import django_tables2 as tables + +from utilities.tables import BaseTable, TagColumn, ToggleColumn +from ipam.models import * + +__all__ = ( + 'ServiceTable', +) + + +# +# Services +# + +class ServiceTable(BaseTable): + pk = ToggleColumn() + name = tables.Column( + linkify=True + ) + parent = tables.Column( + linkify=True, + order_by=('device', 'virtual_machine') + ) + ports = tables.TemplateColumn( + template_code='{{ record.port_list }}', + verbose_name='Ports' + ) + tags = TagColumn( + url_name='ipam:service_list' + ) + + class Meta(BaseTable.Meta): + model = Service + fields = ('pk', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'tags') + default_columns = ('pk', 'name', 'parent', 'protocol', 'ports', 'description') diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py new file mode 100644 index 000000000..4219a8a52 --- /dev/null +++ b/netbox/ipam/tables/vlans.py @@ -0,0 +1,203 @@ +import django_tables2 as tables +from django.utils.safestring import mark_safe +from django_tables2.utils import Accessor + +from dcim.models import Interface +from tenancy.tables import TenantColumn +from utilities.tables import ( + BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn, + ToggleColumn, +) +from virtualization.models import VMInterface +from ipam.models import * + +__all__ = ( + 'InterfaceVLANTable', + 'VLANDevicesTable', + 'VLANGroupTable', + 'VLANMembersTable', + 'VLANTable', + 'VLANVirtualMachinesTable', +) + +AVAILABLE_LABEL = mark_safe('Available') + +VLAN_LINK = """ +{% if record.pk %} + {{ record.vid }} +{% elif perms.ipam.add_vlan %} + {{ record.available }} VLAN{{ record.available|pluralize }} available +{% else %} + {{ record.available }} VLAN{{ record.available|pluralize }} available +{% endif %} +""" + +VLAN_PREFIXES = """ +{% for prefix in record.prefixes.all %} + {{ prefix }}{% if not forloop.last %}
{% endif %} +{% empty %} + — +{% endfor %} +""" + +VLAN_ROLE_LINK = """ +{% if record.role %} + {{ record.role }} +{% else %} + — +{% endif %} +""" + +VLANGROUP_ADD_VLAN = """ +{% with next_vid=record.get_next_available_vid %} + {% if next_vid and perms.ipam.add_vlan %} + + + + {% endif %} +{% endwith %} +""" + +VLAN_MEMBER_TAGGED = """ +{% if record.untagged_vlan_id == object.pk %} + +{% else %} + +{% endif %} +""" + + +# +# VLAN groups +# + +class VLANGroupTable(BaseTable): + pk = ToggleColumn() + name = tables.Column(linkify=True) + scope_type = ContentTypeColumn() + scope = tables.Column( + linkify=True, + orderable=False + ) + vlan_count = LinkedCountColumn( + viewname='ipam:vlan_list', + url_params={'group_id': 'pk'}, + verbose_name='VLANs' + ) + actions = ButtonsColumn( + model=VLANGroup, + prepend_template=VLANGROUP_ADD_VLAN + ) + + class Meta(BaseTable.Meta): + model = VLANGroup + fields = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'slug', 'description', 'actions') + default_columns = ('pk', 'name', 'scope_type', 'scope', 'vlan_count', 'description', 'actions') + + +# +# VLANs +# + +class VLANTable(BaseTable): + pk = ToggleColumn() + vid = tables.TemplateColumn( + template_code=VLAN_LINK, + verbose_name='ID' + ) + site = tables.Column( + linkify=True + ) + group = tables.Column( + linkify=True + ) + tenant = TenantColumn() + status = ChoiceFieldColumn( + default=AVAILABLE_LABEL + ) + role = tables.TemplateColumn( + template_code=VLAN_ROLE_LINK + ) + prefixes = tables.TemplateColumn( + template_code=VLAN_PREFIXES, + orderable=False, + verbose_name='Prefixes' + ) + tags = TagColumn( + url_name='ipam:vlan_list' + ) + + class Meta(BaseTable.Meta): + model = VLAN + fields = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags') + default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') + row_attrs = { + 'class': lambda record: 'success' if not isinstance(record, VLAN) else '', + } + + +class VLANMembersTable(BaseTable): + """ + Base table for Interface and VMInterface assignments + """ + name = tables.Column( + linkify=True, + verbose_name='Interface' + ) + tagged = tables.TemplateColumn( + template_code=VLAN_MEMBER_TAGGED, + orderable=False + ) + + +class VLANDevicesTable(VLANMembersTable): + device = tables.Column( + linkify=True + ) + actions = ButtonsColumn(Interface, buttons=['edit']) + + class Meta(BaseTable.Meta): + model = Interface + fields = ('device', 'name', 'tagged', 'actions') + + +class VLANVirtualMachinesTable(VLANMembersTable): + virtual_machine = tables.Column( + linkify=True + ) + actions = ButtonsColumn(VMInterface, buttons=['edit']) + + class Meta(BaseTable.Meta): + model = VMInterface + fields = ('virtual_machine', 'name', 'tagged', 'actions') + + +class InterfaceVLANTable(BaseTable): + """ + List VLANs assigned to a specific Interface. + """ + vid = tables.Column( + linkify=True, + verbose_name='ID' + ) + tagged = BooleanColumn() + site = tables.Column( + linkify=True + ) + group = tables.Column( + accessor=Accessor('group__name'), + verbose_name='Group' + ) + tenant = TenantColumn() + status = ChoiceFieldColumn() + role = tables.TemplateColumn( + template_code=VLAN_ROLE_LINK + ) + + class Meta(BaseTable.Meta): + model = VLAN + fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') + + def __init__(self, interface, *args, **kwargs): + self.interface = interface + super().__init__(*args, **kwargs) diff --git a/netbox/ipam/tables/vrfs.py b/netbox/ipam/tables/vrfs.py new file mode 100644 index 000000000..bea2a6b1f --- /dev/null +++ b/netbox/ipam/tables/vrfs.py @@ -0,0 +1,74 @@ +import django_tables2 as tables + +from tenancy.tables import TenantColumn +from utilities.tables import BaseTable, BooleanColumn, TagColumn, ToggleColumn +from ipam.models import * + +__all__ = ( + 'RouteTargetTable', + 'VRFTable', +) + +VRF_TARGETS = """ +{% for rt in value.all %} + {{ rt }}{% if not forloop.last %}
{% endif %} +{% empty %} + — +{% endfor %} +""" + + +# +# VRFs +# + +class VRFTable(BaseTable): + pk = ToggleColumn() + name = tables.Column( + linkify=True + ) + rd = tables.Column( + verbose_name='RD' + ) + tenant = TenantColumn() + enforce_unique = BooleanColumn( + verbose_name='Unique' + ) + import_targets = tables.TemplateColumn( + template_code=VRF_TARGETS, + orderable=False + ) + export_targets = tables.TemplateColumn( + template_code=VRF_TARGETS, + orderable=False + ) + tags = TagColumn( + url_name='ipam:vrf_list' + ) + + class Meta(BaseTable.Meta): + model = VRF + fields = ( + 'pk', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tags', + ) + default_columns = ('pk', 'name', 'rd', 'tenant', 'description') + + +# +# Route targets +# + +class RouteTargetTable(BaseTable): + pk = ToggleColumn() + name = tables.Column( + linkify=True + ) + tenant = TenantColumn() + tags = TagColumn( + url_name='ipam:vrf_list' + ) + + class Meta(BaseTable.Meta): + model = RouteTarget + fields = ('pk', 'name', 'tenant', 'description', 'tags') + default_columns = ('pk', 'name', 'tenant', 'description') diff --git a/netbox/tenancy/tables.py b/netbox/tenancy/tables.py index 961d02dcc..c62c641d1 100644 --- a/netbox/tenancy/tables.py +++ b/netbox/tenancy/tables.py @@ -5,6 +5,12 @@ from utilities.tables import ( ) from .models import Tenant, TenantGroup +__all__ = ( + 'TenantColumn', + 'TenantGroupTable', + 'TenantTable', +) + # # Table columns