Explorar o código

Move configure_table() logic to NetBoxTable.configure()

jeremystretch %!s(int64=4) %!d(string=hai) anos
pai
achega
23a80770e1

+ 11 - 0
docs/plugins/development/tables.md

@@ -35,3 +35,14 @@ class MyModelTable(NetBoxTable):
         fields = ('pk', 'id', 'name', ...)
         fields = ('pk', 'id', 'name', ...)
         default_columns = ('pk', 'name', ...)
         default_columns = ('pk', 'name', ...)
 ```
 ```
+
+### Table Configuration
+
+The NetBoxTable class supports dynamic configuration to support pagination and to effect user preferences. To configure a table for a specific request, simply call its `configure()` method and pass the current HTTPRequest object. For example:
+
+```python
+table = MyModelTable(data=MyModel.objects.all())
+table.configure(request)
+```
+
+If using a generic view provided by NetBox, table configuration is handled automatically.

+ 3 - 4
netbox/circuits/views.py

@@ -5,7 +5,6 @@ from django.shortcuts import get_object_or_404, redirect, render
 
 
 from netbox.views import generic
 from netbox.views import generic
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
 from .models import *
 from .models import *
@@ -34,7 +33,7 @@ class ProviderView(generic.ObjectView):
             'type', 'tenant', 'terminations__site'
             'type', 'tenant', 'terminations__site'
         )
         )
         circuits_table = tables.CircuitTable(circuits, exclude=('provider',))
         circuits_table = tables.CircuitTable(circuits, exclude=('provider',))
-        configure_table(circuits_table, request)
+        circuits_table.configure(request)
 
 
         return {
         return {
             'circuits_table': circuits_table,
             'circuits_table': circuits_table,
@@ -95,7 +94,7 @@ class ProviderNetworkView(generic.ObjectView):
             'type', 'tenant', 'terminations__site'
             'type', 'tenant', 'terminations__site'
         )
         )
         circuits_table = tables.CircuitTable(circuits)
         circuits_table = tables.CircuitTable(circuits)
-        configure_table(circuits_table, request)
+        circuits_table.configure(request)
 
 
         return {
         return {
             'circuits_table': circuits_table,
             'circuits_table': circuits_table,
@@ -149,7 +148,7 @@ class CircuitTypeView(generic.ObjectView):
     def get_extra_context(self, request, instance):
     def get_extra_context(self, request, instance):
         circuits = Circuit.objects.restrict(request.user, 'view').filter(type=instance)
         circuits = Circuit.objects.restrict(request.user, 'view').filter(type=instance)
         circuits_table = tables.CircuitTable(circuits, exclude=('type',))
         circuits_table = tables.CircuitTable(circuits, exclude=('type',))
-        configure_table(circuits_table, request)
+        circuits_table.configure(request)
 
 
         return {
         return {
             'circuits_table': circuits_table,
             'circuits_table': circuits_table,

+ 7 - 8
netbox/dcim/views.py

@@ -20,7 +20,6 @@ from netbox.views import generic
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.paginator import EnhancedPaginator, get_paginate_count
 from utilities.permissions import get_permission_for_model
 from utilities.permissions import get_permission_for_model
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
 from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
@@ -165,7 +164,7 @@ class RegionView(generic.ObjectView):
             region=instance
             region=instance
         )
         )
         sites_table = tables.SiteTable(sites, exclude=('region',))
         sites_table = tables.SiteTable(sites, exclude=('region',))
-        configure_table(sites_table, request)
+        sites_table.configure(request)
 
 
         return {
         return {
             'child_regions_table': child_regions_table,
             'child_regions_table': child_regions_table,
@@ -250,7 +249,7 @@ class SiteGroupView(generic.ObjectView):
             group=instance
             group=instance
         )
         )
         sites_table = tables.SiteTable(sites, exclude=('group',))
         sites_table = tables.SiteTable(sites, exclude=('group',))
-        configure_table(sites_table, request)
+        sites_table.configure(request)
 
 
         return {
         return {
             'child_groups_table': child_groups_table,
             'child_groups_table': child_groups_table,
@@ -422,7 +421,7 @@ class LocationView(generic.ObjectView):
             cumulative=True
             cumulative=True
         ).filter(pk__in=location_ids).exclude(pk=instance.pk)
         ).filter(pk__in=location_ids).exclude(pk=instance.pk)
         child_locations_table = tables.LocationTable(child_locations)
         child_locations_table = tables.LocationTable(child_locations)
-        configure_table(child_locations_table, request)
+        child_locations_table.configure(request)
 
 
         return {
         return {
             'rack_count': rack_count,
             'rack_count': rack_count,
@@ -493,7 +492,7 @@ class RackRoleView(generic.ObjectView):
         )
         )
 
 
         racks_table = tables.RackTable(racks, exclude=('role', 'get_utilization', 'get_power_utilization'))
         racks_table = tables.RackTable(racks, exclude=('role', 'get_utilization', 'get_power_utilization'))
-        configure_table(racks_table, request)
+        racks_table.configure(request)
 
 
         return {
         return {
             'racks_table': racks_table,
             'racks_table': racks_table,
@@ -743,7 +742,7 @@ class ManufacturerView(generic.ObjectView):
         )
         )
 
 
         devicetypes_table = tables.DeviceTypeTable(devicetypes, exclude=('manufacturer',))
         devicetypes_table = tables.DeviceTypeTable(devicetypes, exclude=('manufacturer',))
-        configure_table(devicetypes_table, request)
+        devicetypes_table.configure(request)
 
 
         return {
         return {
             'devicetypes_table': devicetypes_table,
             'devicetypes_table': devicetypes_table,
@@ -1437,7 +1436,7 @@ class DeviceRoleView(generic.ObjectView):
             device_role=instance
             device_role=instance
         )
         )
         devices_table = tables.DeviceTable(devices, exclude=('device_role',))
         devices_table = tables.DeviceTable(devices, exclude=('device_role',))
-        configure_table(devices_table, request)
+        devices_table.configure(request)
 
 
         return {
         return {
             'devices_table': devices_table,
             'devices_table': devices_table,
@@ -1501,7 +1500,7 @@ class PlatformView(generic.ObjectView):
             platform=instance
             platform=instance
         )
         )
         devices_table = tables.DeviceTable(devices, exclude=('platform',))
         devices_table = tables.DeviceTable(devices, exclude=('platform',))
-        configure_table(devices_table, request)
+        devices_table.configure(request)
 
 
         return {
         return {
             'devices_table': devices_table,
             'devices_table': devices_table,

+ 3 - 4
netbox/extras/views.py

@@ -11,7 +11,6 @@ from rq import Worker
 from netbox.views import generic
 from netbox.views import generic
 from utilities.forms import ConfirmationForm
 from utilities.forms import ConfirmationForm
 from utilities.htmx import is_htmx
 from utilities.htmx import is_htmx
-from netbox.tables import configure_table
 from utilities.utils import copy_safe_request, count_related, normalize_querydict, shallow_compare_dict
 from utilities.utils import copy_safe_request, count_related, normalize_querydict, shallow_compare_dict
 from utilities.views import ContentTypePermissionRequiredMixin
 from utilities.views import ContentTypePermissionRequiredMixin
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
@@ -215,7 +214,7 @@ class TagView(generic.ObjectView):
             data=tagged_items,
             data=tagged_items,
             orderable=False
             orderable=False
         )
         )
-        configure_table(taggeditem_table, request)
+        taggeditem_table.configure(request)
 
 
         object_types = [
         object_types = [
             {
             {
@@ -451,7 +450,7 @@ class ObjectChangeLogView(View):
             data=objectchanges,
             data=objectchanges,
             orderable=False
             orderable=False
         )
         )
-        configure_table(objectchanges_table, request)
+        objectchanges_table.configure(request)
 
 
         # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
         # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
         # fall back to using base.html.
         # fall back to using base.html.
@@ -571,7 +570,7 @@ class ObjectJournalView(View):
             assigned_object_id=obj.pk
             assigned_object_id=obj.pk
         )
         )
         journalentry_table = tables.ObjectJournalTable(journalentries)
         journalentry_table = tables.ObjectJournalTable(journalentries)
-        configure_table(journalentry_table, request)
+        journalentry_table.configure(request)
 
 
         if request.user.has_perm('extras.add_journalentry'):
         if request.user.has_perm('extras.add_journalentry'):
             form = forms.JournalEntryForm(
             form = forms.JournalEntryForm(

+ 5 - 6
netbox/ipam/views.py

@@ -8,7 +8,6 @@ from dcim.filtersets import InterfaceFilterSet
 from dcim.models import Interface, Site
 from dcim.models import Interface, Site
 from dcim.tables import SiteTable
 from dcim.tables import SiteTable
 from netbox.views import generic
 from netbox.views import generic
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from virtualization.filtersets import VMInterfaceFilterSet
 from virtualization.filtersets import VMInterfaceFilterSet
 from virtualization.models import VMInterface
 from virtualization.models import VMInterface
@@ -161,7 +160,7 @@ class RIRView(generic.ObjectView):
             rir=instance
             rir=instance
         )
         )
         aggregates_table = tables.AggregateTable(aggregates, exclude=('rir', 'utilization'))
         aggregates_table = tables.AggregateTable(aggregates, exclude=('rir', 'utilization'))
-        configure_table(aggregates_table, request)
+        aggregates_table.configure(request)
 
 
         return {
         return {
             'aggregates_table': aggregates_table,
             'aggregates_table': aggregates_table,
@@ -219,7 +218,7 @@ class ASNView(generic.ObjectView):
     def get_extra_context(self, request, instance):
     def get_extra_context(self, request, instance):
         sites = instance.sites.restrict(request.user, 'view')
         sites = instance.sites.restrict(request.user, 'view')
         sites_table = SiteTable(sites)
         sites_table = SiteTable(sites)
-        configure_table(sites_table, request)
+        sites_table.configure(request)
 
 
         return {
         return {
             'sites_table': sites_table,
             'sites_table': sites_table,
@@ -357,7 +356,7 @@ class RoleView(generic.ObjectView):
         )
         )
 
 
         prefixes_table = tables.PrefixTable(prefixes, exclude=('role', 'utilization'))
         prefixes_table = tables.PrefixTable(prefixes, exclude=('role', 'utilization'))
-        configure_table(prefixes_table, request)
+        prefixes_table.configure(request)
 
 
         return {
         return {
             'prefixes_table': prefixes_table,
             'prefixes_table': prefixes_table,
@@ -662,7 +661,7 @@ class IPAddressView(generic.ObjectView):
             vrf=instance.vrf, address__net_contained_or_equal=str(instance.address)
             vrf=instance.vrf, address__net_contained_or_equal=str(instance.address)
         )
         )
         related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
         related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
-        configure_table(related_ips_table, request)
+        related_ips_table.configure(request)
 
 
         return {
         return {
             'parent_prefixes_table': parent_prefixes_table,
             'parent_prefixes_table': parent_prefixes_table,
@@ -798,7 +797,7 @@ class VLANGroupView(generic.ObjectView):
         vlans_table = tables.VLANTable(vlans, exclude=('site', 'group', 'prefixes'))
         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'):
         if request.user.has_perm('ipam.change_vlan') or request.user.has_perm('ipam.delete_vlan'):
             vlans_table.columns.show('pk')
             vlans_table.columns.show('pk')
-        configure_table(vlans_table, request)
+        vlans_table.configure(request)
 
 
         # Compile permissions list for rendering the object table
         # Compile permissions list for rendering the object table
         permissions = {
         permissions = {

+ 0 - 27
netbox/netbox/tables/__init__.py

@@ -1,29 +1,2 @@
-from django_tables2 import RequestConfig
-
-from utilities.paginator import EnhancedPaginator, get_paginate_count
 from .columns import *
 from .columns import *
 from .tables import *
 from .tables import *
-
-
-def configure_table(table, request):
-    """
-    Paginate a table given a request context.
-    """
-    # Save ordering preference
-    if request.user.is_authenticated:
-        table_name = table.__class__.__name__
-        if table.prefixed_order_by_field in request.GET:
-            # If an ordering has been specified as a query parameter, save it as the
-            # user's preferred ordering for this table.
-            ordering = request.GET.getlist(table.prefixed_order_by_field)
-            request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True)
-        elif ordering := request.user.config.get(f'tables.{table_name}.ordering'):
-            # If no ordering has been specified, set the preferred ordering (if any).
-            table.order_by = ordering
-
-    # Paginate the table results
-    paginate = {
-        'paginator_class': EnhancedPaginator,
-        'per_page': get_paginate_count(request)
-    }
-    RequestConfig(request, paginate).configure(table)

+ 25 - 0
netbox/netbox/tables/tables.py

@@ -8,6 +8,7 @@ from django_tables2.data import TableQuerysetData
 
 
 from extras.models import CustomField, CustomLink
 from extras.models import CustomField, CustomLink
 from netbox.tables import columns
 from netbox.tables import columns
+from utilities.paginator import EnhancedPaginator, get_paginate_count
 
 
 __all__ = (
 __all__ = (
     'BaseTable',
     'BaseTable',
@@ -166,3 +167,27 @@ class NetBoxTable(BaseTable):
         ])
         ])
 
 
         super().__init__(*args, extra_columns=extra_columns, **kwargs)
         super().__init__(*args, extra_columns=extra_columns, **kwargs)
+
+    def configure(self, request):
+        """
+        Configure the table for a specific request context. This performs pagination and records
+        the user's preferred ordering logic.
+        """
+        # Save ordering preference
+        if request.user.is_authenticated:
+            table_name = self.__class__.__name__
+            if self.prefixed_order_by_field in request.GET:
+                # If an ordering has been specified as a query parameter, save it as the
+                # user's preferred ordering for this table.
+                ordering = request.GET.getlist(self.prefixed_order_by_field)
+                request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True)
+            elif ordering := request.user.config.get(f'tables.{table_name}.ordering'):
+                # If no ordering has been specified, set the preferred ordering (if any).
+                self.order_by = ordering
+
+        # Paginate the table results
+        paginate = {
+            'paginator_class': EnhancedPaginator,
+            'per_page': get_paginate_count(request)
+        }
+        tables.RequestConfig(request, paginate).configure(self)

+ 1 - 2
netbox/netbox/views/generic/bulk_views.py

@@ -14,7 +14,6 @@ from django_tables2.export import TableExport
 
 
 from extras.models import ExportTemplate
 from extras.models import ExportTemplate
 from extras.signals import clear_webhooks
 from extras.signals import clear_webhooks
-from netbox.tables import configure_table
 from utilities.error_handlers import handle_protectederror
 from utilities.error_handlers import handle_protectederror
 from utilities.exceptions import PermissionsViolation
 from utilities.exceptions import PermissionsViolation
 from utilities.forms import (
 from utilities.forms import (
@@ -169,7 +168,7 @@ class ObjectListView(BaseMultiObjectView):
 
 
         # Render the objects table
         # Render the objects table
         table = self.get_table(request, permissions)
         table = self.get_table(request, permissions)
-        configure_table(table, request)
+        table.configure(request)
 
 
         # If this is an HTMX request, return only the rendered table HTML
         # If this is an HTMX request, return only the rendered table HTML
         if is_htmx(request):
         if is_htmx(request):

+ 1 - 2
netbox/netbox/views/generic/object_views.py

@@ -17,7 +17,6 @@ from utilities.exceptions import AbortTransaction, PermissionsViolation
 from utilities.forms import ConfirmationForm, ImportForm, restrict_form_fields
 from utilities.forms import ConfirmationForm, ImportForm, restrict_form_fields
 from utilities.htmx import is_htmx
 from utilities.htmx import is_htmx
 from utilities.permissions import get_permission_for_model
 from utilities.permissions import get_permission_for_model
-from netbox.tables import configure_table
 from utilities.utils import normalize_querydict, prepare_cloned_fields
 from utilities.utils import normalize_querydict, prepare_cloned_fields
 from utilities.views import GetReturnURLMixin
 from utilities.views import GetReturnURLMixin
 from .base import BaseObjectView
 from .base import BaseObjectView
@@ -124,7 +123,7 @@ class ObjectChildrenView(ObjectView):
         # Determine whether to display bulk action checkboxes
         # Determine whether to display bulk action checkboxes
         if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']):
         if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']):
             table.columns.show('pk')
             table.columns.show('pk')
-        configure_table(table, request)
+        table.configure(request)
 
 
         # If this is an HTMX request, return only the rendered table HTML
         # If this is an HTMX request, return only the rendered table HTML
         if is_htmx(request):
         if is_htmx(request):

+ 4 - 5
netbox/tenancy/views.py

@@ -5,7 +5,6 @@ from circuits.models import Circuit
 from dcim.models import Cable, Device, Location, Rack, RackReservation, Site
 from dcim.models import Cable, Device, Location, Rack, RackReservation, Site
 from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF, ASN
 from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF, ASN
 from netbox.views import generic
 from netbox.views import generic
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from virtualization.models import VirtualMachine, Cluster
 from virtualization.models import VirtualMachine, Cluster
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
@@ -37,7 +36,7 @@ class TenantGroupView(generic.ObjectView):
             group=instance
             group=instance
         )
         )
         tenants_table = tables.TenantTable(tenants, exclude=('group',))
         tenants_table = tables.TenantTable(tenants, exclude=('group',))
-        configure_table(tenants_table, request)
+        tenants_table.configure(request)
 
 
         return {
         return {
             'tenants_table': tenants_table,
             'tenants_table': tenants_table,
@@ -186,7 +185,7 @@ class ContactGroupView(generic.ObjectView):
             group=instance
             group=instance
         )
         )
         contacts_table = tables.ContactTable(contacts, exclude=('group',))
         contacts_table = tables.ContactTable(contacts, exclude=('group',))
-        configure_table(contacts_table, request)
+        contacts_table.configure(request)
 
 
         return {
         return {
             'child_groups_table': child_groups_table,
             'child_groups_table': child_groups_table,
@@ -253,7 +252,7 @@ class ContactRoleView(generic.ObjectView):
         )
         )
         contacts_table = tables.ContactAssignmentTable(contact_assignments)
         contacts_table = tables.ContactAssignmentTable(contact_assignments)
         contacts_table.columns.hide('role')
         contacts_table.columns.hide('role')
-        configure_table(contacts_table, request)
+        contacts_table.configure(request)
 
 
         return {
         return {
             'contacts_table': contacts_table,
             'contacts_table': contacts_table,
@@ -310,7 +309,7 @@ class ContactView(generic.ObjectView):
         )
         )
         assignments_table = tables.ContactAssignmentTable(contact_assignments)
         assignments_table = tables.ContactAssignmentTable(contact_assignments)
         assignments_table.columns.hide('contact')
         assignments_table.columns.hide('contact')
-        configure_table(assignments_table, request)
+        assignments_table.configure(request)
 
 
         return {
         return {
             'assignments_table': assignments_table,
             'assignments_table': assignments_table,

+ 1 - 2
netbox/users/tests/test_preferences.py

@@ -6,7 +6,6 @@ from django.urls import reverse
 from dcim.models import Site
 from dcim.models import Site
 from dcim.tables import SiteTable
 from dcim.tables import SiteTable
 from users.preferences import UserPreference
 from users.preferences import UserPreference
-from netbox.tables import configure_table
 from utilities.testing import TestCase
 from utilities.testing import TestCase
 
 
 
 
@@ -60,5 +59,5 @@ class UserPreferencesTest(TestCase):
         table = SiteTable(Site.objects.all())
         table = SiteTable(Site.objects.all())
         request = RequestFactory().get(url)
         request = RequestFactory().get(url)
         request.user = self.user
         request.user = self.user
-        configure_table(table, request)
+        table.configure(request)
         self.assertEqual(table.order_by, ('-status',))
         self.assertEqual(table.order_by, ('-status',))

+ 2 - 3
netbox/virtualization/views.py

@@ -11,7 +11,6 @@ from extras.views import ObjectConfigContextView
 from ipam.models import IPAddress, Service
 from ipam.models import IPAddress, Service
 from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
 from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
 from netbox.views import generic
 from netbox.views import generic
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
 from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
@@ -41,7 +40,7 @@ class ClusterTypeView(generic.ObjectView):
             vm_count=count_related(VirtualMachine, 'cluster')
             vm_count=count_related(VirtualMachine, 'cluster')
         )
         )
         clusters_table = tables.ClusterTable(clusters, exclude=('type',))
         clusters_table = tables.ClusterTable(clusters, exclude=('type',))
-        configure_table(clusters_table, request)
+        clusters_table.configure(request)
 
 
         return {
         return {
             'clusters_table': clusters_table,
             'clusters_table': clusters_table,
@@ -103,7 +102,7 @@ class ClusterGroupView(generic.ObjectView):
             vm_count=count_related(VirtualMachine, 'cluster')
             vm_count=count_related(VirtualMachine, 'cluster')
         )
         )
         clusters_table = tables.ClusterTable(clusters, exclude=('group',))
         clusters_table = tables.ClusterTable(clusters, exclude=('group',))
-        configure_table(clusters_table, request)
+        clusters_table.configure(request)
 
 
         return {
         return {
             'clusters_table': clusters_table,
             'clusters_table': clusters_table,

+ 2 - 3
netbox/wireless/views.py

@@ -1,6 +1,5 @@
 from dcim.models import Interface
 from dcim.models import Interface
 from netbox.views import generic
 from netbox.views import generic
-from netbox.tables import configure_table
 from utilities.utils import count_related
 from utilities.utils import count_related
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
 from .models import *
 from .models import *
@@ -31,7 +30,7 @@ class WirelessLANGroupView(generic.ObjectView):
             group=instance
             group=instance
         )
         )
         wirelesslans_table = tables.WirelessLANTable(wirelesslans, exclude=('group',))
         wirelesslans_table = tables.WirelessLANTable(wirelesslans, exclude=('group',))
-        configure_table(wirelesslans_table, request)
+        wirelesslans_table.configure(request)
 
 
         return {
         return {
             'wirelesslans_table': wirelesslans_table,
             'wirelesslans_table': wirelesslans_table,
@@ -99,7 +98,7 @@ class WirelessLANView(generic.ObjectView):
             wireless_lans=instance
             wireless_lans=instance
         )
         )
         interfaces_table = tables.WirelessLANInterfacesTable(attached_interfaces)
         interfaces_table = tables.WirelessLANInterfacesTable(attached_interfaces)
-        configure_table(interfaces_table, request)
+        interfaces_table.configure(request)
 
 
         return {
         return {
             'interfaces_table': interfaces_table,
             'interfaces_table': interfaces_table,