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/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/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/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..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,8 +451,7 @@ class RackRoleView(generic.ObjectView):
role=instance
)
- racks_table = tables.RackTable(racks)
- racks_table.columns.hide('role')
+ racks_table = tables.RackTable(racks, exclude=('role', 'get_utilization', 'get_power_utilization'))
paginate_table(racks_table, request)
return {
@@ -505,7 +502,7 @@ class RackListView(generic.ObjectListView):
)
filterset = filtersets.RackFilterSet
filterset_form = forms.RackFilterForm
- table = tables.RackDetailTable
+ table = tables.RackTable
class RackElevationListView(generic.ObjectListView):
@@ -704,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 {
@@ -1165,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 {
@@ -1231,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 {
@@ -1878,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/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 55%
rename from netbox/ipam/tables.py
rename to netbox/ipam/tables/ip.py
index 5afb6a9c9..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
@@ -215,13 +116,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 +127,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 +227,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 +235,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 +244,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 +312,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 +325,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):
@@ -501,173 +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
- )
-
- 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):
- fields = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags')
- default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description')
-
-
-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/ipam/views.py b/netbox/ipam/views.py
index 64ca5bc43..015d47065 100644
--- a/netbox/ipam/views.py
+++ b/netbox/ipam/views.py
@@ -155,9 +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 = tables.AggregateTable(aggregates, exclude=('rir', 'utilization'))
paginate_table(aggregates_table, request)
return {
@@ -207,7 +205,7 @@ class AggregateListView(generic.ObjectListView):
)
filterset = filtersets.AggregateFilterSet
filterset_form = forms.AggregateFilterForm
- table = tables.AggregateDetailTable
+ table = tables.AggregateTable
class AggregateView(generic.ObjectView):
@@ -227,7 +225,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 +294,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 +337,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 +360,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 +374,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 +401,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 +604,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 +618,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 +773,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 +832,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 +842,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 %}