1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Introduced SearchTable for improved performance

This commit is contained in:
Jeremy Stretch
2017-03-29 16:05:23 -04:00
parent d04436aa0a
commit a5dc91c175
10 changed files with 290 additions and 144 deletions

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from utilities.tables import BaseTable, ToggleColumn from utilities.tables import BaseTable, SearchTable, ToggleColumn
from .models import Circuit, CircuitType, Provider from .models import Circuit, CircuitType, Provider
@ -19,9 +19,7 @@ CIRCUITTYPE_ACTIONS = """
class ProviderTable(BaseTable): class ProviderTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn('circuits:provider', args=[Accessor('slug')], verbose_name='Name') name = tables.LinkColumn()
asn = tables.Column(verbose_name='ASN')
account = tables.Column(verbose_name='Account')
circuit_count = tables.Column(accessor=Accessor('count_circuits'), verbose_name='Circuits') circuit_count = tables.Column(accessor=Accessor('count_circuits'), verbose_name='Circuits')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
@ -29,17 +27,25 @@ class ProviderTable(BaseTable):
fields = ('pk', 'name', 'asn', 'account', 'circuit_count') fields = ('pk', 'name', 'asn', 'account', 'circuit_count')
class ProviderSearchTable(SearchTable):
name = tables.LinkColumn()
class Meta(SearchTable.Meta):
model = Provider
fields = ('name', 'asn', 'account')
# #
# Circuit types # Circuit types
# #
class CircuitTypeTable(BaseTable): class CircuitTypeTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn(verbose_name='Name') name = tables.LinkColumn()
circuit_count = tables.Column(verbose_name='Circuits') circuit_count = tables.Column(verbose_name='Circuits')
slug = tables.Column(verbose_name='Slug') actions = tables.TemplateColumn(
actions = tables.TemplateColumn(template_code=CIRCUITTYPE_ACTIONS, attrs={'td': {'class': 'text-right'}}, template_code=CIRCUITTYPE_ACTIONS, attrs={'td': {'class': 'text-right'}}, verbose_name=''
verbose_name='') )
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = CircuitType model = CircuitType
@ -52,16 +58,28 @@ class CircuitTypeTable(BaseTable):
class CircuitTable(BaseTable): class CircuitTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
cid = tables.LinkColumn('circuits:circuit', args=[Accessor('pk')], verbose_name='ID') cid = tables.LinkColumn(verbose_name='ID')
type = tables.Column(verbose_name='Type') provider = tables.LinkColumn('circuits:provider', args=[Accessor('provider.slug')])
provider = tables.LinkColumn('circuits:provider', args=[Accessor('provider.slug')], verbose_name='Provider') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') a_side = tables.LinkColumn(
a_side = tables.LinkColumn('dcim:site', accessor=Accessor('termination_a.site'), orderable=False, 'dcim:site', accessor=Accessor('termination_a.site'), orderable=False,
args=[Accessor('termination_a.site.slug')]) args=[Accessor('termination_a.site.slug')]
z_side = tables.LinkColumn('dcim:site', accessor=Accessor('termination_z.site'), orderable=False, )
args=[Accessor('termination_z.site.slug')]) z_side = tables.LinkColumn(
description = tables.Column(verbose_name='Description') 'dcim:site', accessor=Accessor('termination_z.site'), orderable=False,
args=[Accessor('termination_z.site.slug')]
)
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Circuit model = Circuit
fields = ('pk', 'cid', 'type', 'provider', 'tenant', 'a_side', 'z_side', 'description') fields = ('pk', 'cid', 'type', 'provider', 'tenant', 'a_side', 'z_side', 'description')
class CircuitSearchTable(SearchTable):
cid = tables.LinkColumn(verbose_name='ID')
provider = tables.LinkColumn('circuits:provider', args=[Accessor('provider.slug')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
class Meta(SearchTable.Meta):
model = Circuit
fields = ('cid', 'type', 'provider', 'tenant', 'description')

View File

@ -8,9 +8,9 @@ from tenancy.models import Tenant
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
from .models import ( from .models import (
ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
DeviceBayTemplate, DeviceRole, DeviceType, IFACE_FF_LAG, Interface, InterfaceConnection, InterfaceTemplate, DeviceBayTemplate, DeviceRole, DeviceType, IFACE_FF_LAG, Interface, InterfaceTemplate, Manufacturer, InventoryItem,
Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation,
RackReservation, RackRole, Region, Site, VIRTUAL_IFACE_TYPES, RackRole, Region, Site, VIRTUAL_IFACE_TYPES,
) )

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from utilities.tables import BaseTable, ToggleColumn from utilities.tables import BaseTable, SearchTable, ToggleColumn
from .models import ( from .models import (
ConsolePort, ConsolePortTemplate, ConsoleServerPortTemplate, Device, DeviceBayTemplate, DeviceRole, DeviceType, ConsolePort, ConsolePortTemplate, ConsoleServerPortTemplate, Device, DeviceBayTemplate, DeviceRole, DeviceType,
@ -136,11 +136,9 @@ class RegionTable(BaseTable):
class SiteTable(BaseTable): class SiteTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn('dcim:site', args=[Accessor('slug')], verbose_name='Name') name = tables.LinkColumn()
facility = tables.Column(verbose_name='Facility') region = tables.TemplateColumn(template_code=SITE_REGION_LINK)
region = tables.TemplateColumn(template_code=SITE_REGION_LINK, verbose_name='Region') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
asn = tables.Column(verbose_name='ASN')
rack_count = tables.Column(accessor=Accessor('count_racks'), orderable=False, verbose_name='Racks') rack_count = tables.Column(accessor=Accessor('count_racks'), orderable=False, verbose_name='Racks')
device_count = tables.Column(accessor=Accessor('count_devices'), orderable=False, verbose_name='Devices') device_count = tables.Column(accessor=Accessor('count_devices'), orderable=False, verbose_name='Devices')
prefix_count = tables.Column(accessor=Accessor('count_prefixes'), orderable=False, verbose_name='Prefixes') prefix_count = tables.Column(accessor=Accessor('count_prefixes'), orderable=False, verbose_name='Prefixes')
@ -155,6 +153,16 @@ class SiteTable(BaseTable):
) )
class SiteSearchTable(SearchTable):
name = tables.LinkColumn()
region = tables.TemplateColumn(template_code=SITE_REGION_LINK)
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
class Meta(SearchTable.Meta):
model = Site
fields = ('name', 'facility', 'region', 'tenant', 'asn')
# #
# Rack groups # Rack groups
# #
@ -197,20 +205,33 @@ class RackRoleTable(BaseTable):
class RackTable(BaseTable): class RackTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn('dcim:rack', args=[Accessor('pk')], verbose_name='Name') name = tables.LinkColumn()
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site') site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group') group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
facility_id = tables.Column(verbose_name='Facility ID') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') role = tables.TemplateColumn(RACK_ROLE)
role = tables.TemplateColumn(RACK_ROLE, verbose_name='Role')
u_height = tables.TemplateColumn("{{ record.u_height }}U", verbose_name='Height') u_height = tables.TemplateColumn("{{ record.u_height }}U", verbose_name='Height')
devices = tables.Column(accessor=Accessor('device_count'), verbose_name='Devices') devices = tables.Column(accessor=Accessor('device_count'))
get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization') get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Rack model = Rack
fields = ('pk', 'name', 'site', 'group', 'facility_id', 'tenant', 'role', 'u_height', 'devices', fields = (
'get_utilization') 'pk', 'name', 'site', 'group', 'facility_id', 'tenant', 'role', 'u_height', 'devices', 'get_utilization'
)
class RackSearchTable(SearchTable):
name = tables.LinkColumn()
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
role = tables.TemplateColumn(RACK_ROLE)
u_height = tables.TemplateColumn("{{ record.u_height }}U", verbose_name='Height')
class Meta(SearchTable.Meta):
model = Rack
fields = ('name', 'site', 'group', 'facility_id', 'tenant', 'role', 'u_height')
class RackImportTable(BaseTable): class RackImportTable(BaseTable):
@ -249,9 +270,7 @@ class ManufacturerTable(BaseTable):
class DeviceTypeTable(BaseTable): class DeviceTypeTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
manufacturer = tables.Column(verbose_name='Manufacturer')
model = tables.LinkColumn('dcim:devicetype', args=[Accessor('pk')], verbose_name='Device Type') model = tables.LinkColumn('dcim:devicetype', args=[Accessor('pk')], verbose_name='Device Type')
part_number = tables.Column(verbose_name='Part Number')
is_full_depth = tables.BooleanColumn(verbose_name='Full Depth') is_full_depth = tables.BooleanColumn(verbose_name='Full Depth')
is_console_server = tables.BooleanColumn(verbose_name='CS') is_console_server = tables.BooleanColumn(verbose_name='CS')
is_pdu = tables.BooleanColumn(verbose_name='PDU') is_pdu = tables.BooleanColumn(verbose_name='PDU')
@ -267,6 +286,22 @@ class DeviceTypeTable(BaseTable):
) )
class DeviceTypeSearchTable(SearchTable):
model = tables.LinkColumn('dcim:devicetype', args=[Accessor('pk')], verbose_name='Device Type')
is_full_depth = tables.BooleanColumn(verbose_name='Full Depth')
is_console_server = tables.BooleanColumn(verbose_name='CS')
is_pdu = tables.BooleanColumn(verbose_name='PDU')
is_network_device = tables.BooleanColumn(verbose_name='Net')
subdevice_role = tables.TemplateColumn(SUBDEVICE_ROLE_TEMPLATE, verbose_name='Subdevice Role')
class Meta(SearchTable.Meta):
model = DeviceType
fields = (
'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu',
'is_network_device', 'subdevice_role',
)
# #
# Device type components # Device type components
# #
@ -373,22 +408,42 @@ class PlatformTable(BaseTable):
class DeviceTable(BaseTable): class DeviceTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.TemplateColumn(template_code=DEVICE_LINK)
status = tables.TemplateColumn(template_code=STATUS_ICON, verbose_name='') status = tables.TemplateColumn(template_code=STATUS_ICON, verbose_name='')
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site') rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
device_role = tables.TemplateColumn(DEVICE_ROLE, verbose_name='Role') device_role = tables.TemplateColumn(DEVICE_ROLE, verbose_name='Role')
device_type = tables.LinkColumn('dcim:devicetype', args=[Accessor('device_type.pk')], verbose_name='Type', device_type = tables.LinkColumn(
text=lambda record: record.device_type.full_name) 'dcim:devicetype', args=[Accessor('device_type.pk')], verbose_name='Type',
primary_ip = tables.TemplateColumn(orderable=False, verbose_name='IP Address', text=lambda record: record.device_type.full_name
template_code=DEVICE_PRIMARY_IP) )
primary_ip = tables.TemplateColumn(
orderable=False, verbose_name='IP Address', template_code=DEVICE_PRIMARY_IP
)
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Device model = Device
fields = ('pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip') fields = ('pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip')
class DeviceSearchTable(SearchTable):
name = tables.TemplateColumn(template_code=DEVICE_LINK)
status = tables.TemplateColumn(template_code=STATUS_ICON, verbose_name='')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
device_role = tables.TemplateColumn(DEVICE_ROLE, verbose_name='Role')
device_type = tables.LinkColumn(
'dcim:devicetype', args=[Accessor('device_type.pk')], verbose_name='Type',
text=lambda record: record.device_type.full_name
)
class Meta(SearchTable.Meta):
model = Device
fields = ('name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type')
class DeviceImportTable(BaseTable): class DeviceImportTable(BaseTable):
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name') name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from utilities.tables import BaseTable, ToggleColumn from utilities.tables import BaseTable, SearchTable, ToggleColumn
from .models import Aggregate, IPAddress, Prefix, RIR, Role, VLAN, VLANGroup, VRF from .models import Aggregate, IPAddress, Prefix, RIR, Role, VLAN, VLANGroup, VRF
@ -133,16 +133,25 @@ TENANT_LINK = """
class VRFTable(BaseTable): class VRFTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn('ipam:vrf', args=[Accessor('pk')], verbose_name='Name') name = tables.LinkColumn()
rd = tables.Column(verbose_name='RD') rd = tables.Column(verbose_name='RD')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = VRF model = VRF
fields = ('pk', 'name', 'rd', 'tenant', 'description') fields = ('pk', 'name', 'rd', 'tenant', 'description')
class VRFSearchTable(SearchTable):
name = tables.LinkColumn()
rd = tables.Column(verbose_name='RD')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
class Meta(SearchTable.Meta):
model = VRF
fields = ('name', 'rd', 'tenant', 'description')
# #
# RIRs # RIRs
# #
@ -177,18 +186,25 @@ class RIRTable(BaseTable):
class AggregateTable(BaseTable): class AggregateTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
prefix = tables.LinkColumn('ipam:aggregate', args=[Accessor('pk')], verbose_name='Aggregate') prefix = tables.LinkColumn(verbose_name='Aggregate')
rir = tables.Column(verbose_name='RIR')
child_count = tables.Column(verbose_name='Prefixes') child_count = tables.Column(verbose_name='Prefixes')
get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization') get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
date_added = tables.DateColumn(format="Y-m-d", verbose_name='Added') date_added = tables.DateColumn(format="Y-m-d", verbose_name='Added')
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Aggregate model = Aggregate
fields = ('pk', 'prefix', 'rir', 'child_count', 'get_utilization', 'date_added', 'description') fields = ('pk', 'prefix', 'rir', 'child_count', 'get_utilization', 'date_added', 'description')
class AggregateSearchTable(SearchTable):
prefix = tables.LinkColumn(verbose_name='Aggregate')
date_added = tables.DateColumn(format="Y-m-d", verbose_name='Added')
class Meta(SearchTable.Meta):
model = Aggregate
fields = ('prefix', 'rir', 'date_added', 'description')
# #
# Roles # Roles
# #
@ -212,14 +228,13 @@ class RoleTable(BaseTable):
class PrefixTable(BaseTable): class PrefixTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
status = tables.TemplateColumn(STATUS_LABEL, verbose_name='Status') prefix = tables.TemplateColumn(PREFIX_LINK, attrs={'th': {'style': 'padding-left: 17px'}})
prefix = tables.TemplateColumn(PREFIX_LINK, verbose_name='Prefix', attrs={'th': {'style': 'padding-left: 17px'}}) status = tables.TemplateColumn(STATUS_LABEL)
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF') vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
tenant = tables.TemplateColumn(TENANT_LINK, verbose_name='Tenant') tenant = tables.TemplateColumn(TENANT_LINK)
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site') site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN') vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN')
role = tables.TemplateColumn(PREFIX_ROLE_LINK, verbose_name='Role') role = tables.TemplateColumn(PREFIX_ROLE_LINK)
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Prefix model = Prefix
@ -230,12 +245,11 @@ class PrefixTable(BaseTable):
class PrefixBriefTable(BaseTable): class PrefixBriefTable(BaseTable):
prefix = tables.TemplateColumn(PREFIX_LINK_BRIEF, verbose_name='Prefix') prefix = tables.TemplateColumn(PREFIX_LINK_BRIEF)
vrf = tables.LinkColumn('ipam:vrf', args=[Accessor('vrf.pk')], default='Global', verbose_name='VRF') vrf = tables.LinkColumn('ipam:vrf', args=[Accessor('vrf.pk')], default='Global')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site') site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
status = tables.TemplateColumn(STATUS_LABEL, verbose_name='Status') status = tables.TemplateColumn(STATUS_LABEL)
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN') vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')])
role = tables.Column(verbose_name='Role')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Prefix model = Prefix
@ -243,6 +257,20 @@ class PrefixBriefTable(BaseTable):
orderable = False orderable = False
class PrefixSearchTable(SearchTable):
prefix = tables.TemplateColumn(PREFIX_LINK, attrs={'th': {'style': 'padding-left: 17px'}})
status = tables.TemplateColumn(STATUS_LABEL)
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
tenant = tables.TemplateColumn(TENANT_LINK)
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN')
role = tables.TemplateColumn(PREFIX_ROLE_LINK)
class Meta(SearchTable.Meta):
model = Prefix
fields = ('prefix', 'status', 'vrf', 'tenant', 'site', 'vlan', 'role', 'description')
# #
# IPAddresses # IPAddresses
# #
@ -250,13 +278,11 @@ class PrefixBriefTable(BaseTable):
class IPAddressTable(BaseTable): class IPAddressTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
address = tables.TemplateColumn(IPADDRESS_LINK, verbose_name='IP Address') address = tables.TemplateColumn(IPADDRESS_LINK, verbose_name='IP Address')
status = tables.TemplateColumn(STATUS_LABEL, verbose_name='Status') status = tables.TemplateColumn(STATUS_LABEL)
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF') vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
tenant = tables.TemplateColumn(TENANT_LINK, verbose_name='Tenant') tenant = tables.TemplateColumn(TENANT_LINK)
device = tables.LinkColumn('dcim:device', args=[Accessor('interface.device.pk')], orderable=False, device = tables.LinkColumn('dcim:device', args=[Accessor('interface.device.pk')], orderable=False)
verbose_name='Device') interface = tables.Column(orderable=False)
interface = tables.Column(orderable=False, verbose_name='Interface')
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = IPAddress model = IPAddress
@ -268,17 +294,30 @@ class IPAddressTable(BaseTable):
class IPAddressBriefTable(BaseTable): class IPAddressBriefTable(BaseTable):
address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('pk')], verbose_name='IP Address') address = tables.LinkColumn('ipam:ipaddress', args=[Accessor('pk')], verbose_name='IP Address')
device = tables.LinkColumn('dcim:device', args=[Accessor('interface.device.pk')], orderable=False, device = tables.LinkColumn('dcim:device', args=[Accessor('interface.device.pk')], orderable=False)
verbose_name='Device') interface = tables.Column(orderable=False)
interface = tables.Column(orderable=False, verbose_name='Interface') nat_inside = tables.LinkColumn(
nat_inside = tables.LinkColumn('ipam:ipaddress', args=[Accessor('nat_inside.pk')], orderable=False, 'ipam:ipaddress', args=[Accessor('nat_inside.pk')], orderable=False, verbose_name='NAT (Inside)'
verbose_name='NAT (Inside)') )
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = IPAddress model = IPAddress
fields = ('address', 'device', 'interface', 'nat_inside') fields = ('address', 'device', 'interface', 'nat_inside')
class IPAddressSearchTable(SearchTable):
address = tables.TemplateColumn(IPADDRESS_LINK, verbose_name='IP Address')
status = tables.TemplateColumn(STATUS_LABEL)
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
tenant = tables.TemplateColumn(TENANT_LINK)
device = tables.LinkColumn('dcim:device', args=[Accessor('interface.device.pk')], orderable=False)
interface = tables.Column(orderable=False)
class Meta(SearchTable.Meta):
model = IPAddress
fields = ('address', 'status', 'vrf', 'tenant', 'device', 'interface', 'description')
# #
# VLAN groups # VLAN groups
# #
@ -304,15 +343,26 @@ class VLANGroupTable(BaseTable):
class VLANTable(BaseTable): class VLANTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
vid = tables.LinkColumn('ipam:vlan', args=[Accessor('pk')], verbose_name='ID') vid = tables.LinkColumn('ipam:vlan', args=[Accessor('pk')], verbose_name='ID')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site') site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group') group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
name = tables.Column(verbose_name='Name')
prefixes = tables.TemplateColumn(VLAN_PREFIXES, orderable=False, verbose_name='Prefixes') prefixes = tables.TemplateColumn(VLAN_PREFIXES, orderable=False, verbose_name='Prefixes')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant') tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
status = tables.TemplateColumn(STATUS_LABEL, verbose_name='Status') status = tables.TemplateColumn(STATUS_LABEL)
role = tables.TemplateColumn(VLAN_ROLE_LINK, verbose_name='Role') role = tables.TemplateColumn(VLAN_ROLE_LINK)
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = VLAN model = VLAN
fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description') fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description')
class VLANSearchTable(SearchTable):
vid = tables.LinkColumn('ipam:vlan', args=[Accessor('pk')], verbose_name='ID')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
status = tables.TemplateColumn(STATUS_LABEL)
role = tables.TemplateColumn(VLAN_ROLE_LINK)
class Meta(SearchTable.Meta):
model = VLAN
fields = ('vid', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description')

View File

@ -4,26 +4,25 @@ from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.reverse import reverse from rest_framework.reverse import reverse
from django.db.models import Count
from django.shortcuts import render from django.shortcuts import render
from django.views.generic import View from django.views.generic import View
from circuits.filters import CircuitFilter, ProviderFilter from circuits.filters import CircuitFilter, ProviderFilter
from circuits.models import Circuit, Provider from circuits.models import Circuit, Provider
from circuits.tables import CircuitTable, ProviderTable from circuits.tables import CircuitSearchTable, ProviderSearchTable
from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter
from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site
from dcim.tables import DeviceTable, DeviceTypeTable, RackTable, SiteTable from dcim.tables import DeviceSearchTable, DeviceTypeSearchTable, RackSearchTable, SiteSearchTable
from extras.models import UserAction from extras.models import UserAction
from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter
from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF
from ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable from ipam.tables import AggregateSearchTable, IPAddressSearchTable, PrefixSearchTable, VLANSearchTable, VRFSearchTable
from secrets.filters import SecretFilter from secrets.filters import SecretFilter
from secrets.models import Secret from secrets.models import Secret
from secrets.tables import SecretTable from secrets.tables import SecretSearchTable
from tenancy.filters import TenantFilter from tenancy.filters import TenantFilter
from tenancy.models import Tenant from tenancy.models import Tenant
from tenancy.tables import TenantTable from tenancy.tables import TenantSearchTable
from .forms import SearchForm from .forms import SearchForm
@ -31,89 +30,85 @@ SEARCH_MAX_RESULTS = 15
SEARCH_TYPES = { SEARCH_TYPES = {
# Circuits # Circuits
'provider': { 'provider': {
'queryset': Provider.objects.annotate(count_circuits=Count('circuits')), 'queryset': Provider.objects.all(),
'filter': ProviderFilter, 'filter': ProviderFilter,
'table': ProviderTable, 'table': ProviderSearchTable,
'url': 'circuits:provider_list', 'url': 'circuits:provider_list',
}, },
'circuit': { 'circuit': {
'queryset': Circuit.objects.select_related('provider', 'type', 'tenant').prefetch_related( 'queryset': Circuit.objects.select_related('type', 'provider', 'tenant'),
'terminations__site'
),
'filter': CircuitFilter, 'filter': CircuitFilter,
'table': CircuitTable, 'table': CircuitSearchTable,
'url': 'circuits:circuit_list', 'url': 'circuits:circuit_list',
}, },
# DCIM # DCIM
'site': { 'site': {
'queryset': Site.objects.select_related('region', 'tenant'), 'queryset': Site.objects.select_related('region', 'tenant'),
'filter': SiteFilter, 'filter': SiteFilter,
'table': SiteTable, 'table': SiteSearchTable,
'url': 'dcim:site_list', 'url': 'dcim:site_list',
}, },
'rack': { 'rack': {
'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('devices__device_type').annotate(device_count=Count('devices', distinct=True)), 'queryset': Rack.objects.select_related('site', 'group', 'tenant', 'role'),
'filter': RackFilter, 'filter': RackFilter,
'table': RackTable, 'table': RackSearchTable,
'url': 'dcim:rack_list', 'url': 'dcim:rack_list',
}, },
'devicetype': { 'devicetype': {
'queryset': DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances')), 'queryset': DeviceType.objects.select_related('manufacturer'),
'filter': DeviceTypeFilter, 'filter': DeviceTypeFilter,
'table': DeviceTypeTable, 'table': DeviceTypeSearchTable,
'url': 'dcim:devicetype_list', 'url': 'dcim:devicetype_list',
}, },
'device': { 'device': {
'queryset': Device.objects.select_related( 'queryset': Device.objects.select_related('device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack'),
'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6'
),
'filter': DeviceFilter, 'filter': DeviceFilter,
'table': DeviceTable, 'table': DeviceSearchTable,
'url': 'dcim:device_list', 'url': 'dcim:device_list',
}, },
# IPAM # IPAM
'vrf': { 'vrf': {
'queryset': VRF.objects.select_related('tenant'), 'queryset': VRF.objects.select_related('tenant'),
'filter': VRFFilter, 'filter': VRFFilter,
'table': VRFTable, 'table': VRFSearchTable,
'url': 'ipam:vrf_list', 'url': 'ipam:vrf_list',
}, },
'aggregate': { 'aggregate': {
'queryset': Aggregate.objects.select_related('rir'), 'queryset': Aggregate.objects.select_related('rir'),
'filter': AggregateFilter, 'filter': AggregateFilter,
'table': AggregateTable, 'table': AggregateSearchTable,
'url': 'ipam:aggregate_list', 'url': 'ipam:aggregate_list',
}, },
'prefix': { 'prefix': {
'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'), 'queryset': Prefix.objects.select_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'),
'filter': PrefixFilter, 'filter': PrefixFilter,
'table': PrefixTable, 'table': PrefixSearchTable,
'url': 'ipam:prefix_list', 'url': 'ipam:prefix_list',
}, },
'ipaddress': { 'ipaddress': {
'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device'), 'queryset': IPAddress.objects.select_related('vrf__tenant', 'tenant', 'interface__device'),
'filter': IPAddressFilter, 'filter': IPAddressFilter,
'table': IPAddressTable, 'table': IPAddressSearchTable,
'url': 'ipam:ipaddress_list', 'url': 'ipam:ipaddress_list',
}, },
'vlan': { 'vlan': {
'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role').prefetch_related('prefixes'), 'queryset': VLAN.objects.select_related('site', 'group', 'tenant', 'role'),
'filter': VLANFilter, 'filter': VLANFilter,
'table': VLANTable, 'table': VLANSearchTable,
'url': 'ipam:vlan_list', 'url': 'ipam:vlan_list',
}, },
# Secrets # Secrets
'secret': { 'secret': {
'queryset': Secret.objects.select_related('role', 'device'), 'queryset': Secret.objects.select_related('role', 'device'),
'filter': SecretFilter, 'filter': SecretFilter,
'table': SecretTable, 'table': SecretSearchTable,
'url': 'secrets:secret_list', 'url': 'secrets:secret_list',
}, },
# Tenancy # Tenancy
'tenant': { 'tenant': {
'queryset': Tenant.objects.select_related('group'), 'queryset': Tenant.objects.select_related('group'),
'filter': TenantFilter, 'filter': TenantFilter,
'table': TenantTable, 'table': TenantSearchTable,
'url': 'tenancy:tenant_list', 'url': 'tenancy:tenant_list',
}, },
} }
@ -180,17 +175,21 @@ class SearchView(View):
obj_types = SEARCH_TYPES.keys() obj_types = SEARCH_TYPES.keys()
for obj_type in obj_types: for obj_type in obj_types:
queryset = SEARCH_TYPES[obj_type]['queryset'] queryset = SEARCH_TYPES[obj_type]['queryset']
filter = SEARCH_TYPES[obj_type]['filter'] filter_cls = SEARCH_TYPES[obj_type]['filter']
table = SEARCH_TYPES[obj_type]['table'] table = SEARCH_TYPES[obj_type]['table']
url = SEARCH_TYPES[obj_type]['url'] url = SEARCH_TYPES[obj_type]['url']
filtered_queryset = filter({'q': form.cleaned_data['q']}, queryset=queryset).qs
total_count = filtered_queryset.count() # Construct the results table for this object type
if total_count: filtered_queryset = filter_cls({'q': form.cleaned_data['q']}, queryset=queryset).qs
table = table(filtered_queryset)
table.paginate(per_page=SEARCH_MAX_RESULTS)
if table.page:
results.append({ results.append({
'name': queryset.model._meta.verbose_name_plural, 'name': queryset.model._meta.verbose_name_plural,
'table': table(filtered_queryset[:SEARCH_MAX_RESULTS]), 'table': table,
'total': total_count,
'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q']) 'url': '{}?q={}'.format(reverse(url), form.cleaned_data['q'])
}) })

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from utilities.tables import BaseTable, ToggleColumn from utilities.tables import BaseTable, SearchTable, ToggleColumn
from .models import SecretRole, Secret from .models import SecretRole, Secret
@ -36,11 +36,15 @@ class SecretRoleTable(BaseTable):
class SecretTable(BaseTable): class SecretTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
device = tables.LinkColumn('secrets:secret', args=[Accessor('pk')], verbose_name='Device') device = tables.LinkColumn()
role = tables.Column(verbose_name='Role')
name = tables.Column(verbose_name='Name')
last_updated = tables.DateTimeColumn(verbose_name='Last updated')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Secret model = Secret
fields = ('pk', 'device', 'role', 'name', 'last_updated') fields = ('pk', 'device', 'role', 'name', 'last_updated')
class SecretSearchTable(SearchTable):
class Meta(SearchTable.Meta):
model = Secret
fields = ('device', 'role', 'name', 'last_updated')

View File

@ -1,6 +1,8 @@
{% extends '_base.html' %} {% extends '_base.html' %}
{% load form_helpers %} {% load form_helpers %}
{% block title %}Search{% endblock %}
{% block content %} {% block content %}
{% if request.GET.q %} {% if request.GET.q %}
{% include 'search_form.html' with search_form=form %} {% include 'search_form.html' with search_form=form %}
@ -8,33 +10,31 @@
<div class="row"> <div class="row">
<div class="col-md-10"> <div class="col-md-10">
{% for obj_type in results %} {% for obj_type in results %}
<h3 id="{{ obj_type.name }}">{{ obj_type.name|title }}</h3> <h3 id="{{ obj_type.name }}">{{ obj_type.name }}</h3>
{% include 'table.html' with table=obj_type.table %} {% include 'table.html' with table=obj_type.table hide_paginator=True %}
{% if obj_type.total > obj_type.table.rows|length %} {% if obj_type.table.page.has_next %}
<a href="{{ obj_type.url }}" class="btn btn-primary pull-right"> <a href="{{ obj_type.url }}" class="btn btn-primary pull-right">
<span class="fa fa-search" aria-hidden="true"></span> <span class="fa fa-search" aria-hidden="true"></span>
All {{ obj_type.total }} results All {{ obj_type.table.page.paginator.count }} results
</a> </a>
{% endif %} {% endif %}
<div class="clearfix"></div> <div class="clearfix"></div>
{% endfor %} {% endfor %}
</div> </div>
<div class="col-md-2" style="padding-top: 20px;"> <div class="col-md-2" style="padding-top: 20px;">
{% if results %} <div class="panel panel-default">
<div class="panel panel-default"> <div class="panel-heading">
<div class="panel-heading"> <strong>Search Results</strong>
<strong>Search Results</strong>
</div>
<div class="list-group">
{% for obj_type in results %}
<a href="#{{ obj_type.name }}" class="list-group-item">
{{ obj_type.name|title }}
<span class="badge">{{ obj_type.total }}</span>
</a>
{% endfor %}
</div>
</div> </div>
{% endif %} <div class="list-group">
{% for obj_type in results %}
<a href="#{{ obj_type.name }}" class="list-group-item">
{{ obj_type.name }}
<span class="badge">{{ obj_type.table.page.paginator.count }}</span>
</a>
{% endfor %}
</div>
</div>
</div> </div>
</div> </div>
{% else %} {% else %}

View File

@ -4,5 +4,7 @@
{# Extends the stock django_tables2 template to provide custom formatting of the pagination controls #} {# Extends the stock django_tables2 template to provide custom formatting of the pagination controls #}
{% block pagination %} {% block pagination %}
{% include 'paginator.html' %} {% if not hide_paginator %}
{% include 'paginator.html' %}
{% endif %}
{% endblock pagination %} {% endblock pagination %}

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from utilities.tables import BaseTable, ToggleColumn from utilities.tables import BaseTable, SearchTable, ToggleColumn
from .models import Tenant, TenantGroup from .models import Tenant, TenantGroup
@ -36,10 +36,15 @@ class TenantGroupTable(BaseTable):
class TenantTable(BaseTable): class TenantTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.LinkColumn('tenancy:tenant', args=[Accessor('slug')], verbose_name='Name') name = tables.LinkColumn()
group = tables.Column(verbose_name='Group')
description = tables.Column(verbose_name='Description')
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Tenant model = Tenant
fields = ('pk', 'name', 'group', 'description') fields = ('pk', 'name', 'group', 'description')
class TenantSearchTable(SearchTable):
class Meta(SearchTable.Meta):
model = Tenant
fields = ('name', 'group', 'description')

View File

@ -4,7 +4,9 @@ from django.utils.safestring import mark_safe
class BaseTable(tables.Table): class BaseTable(tables.Table):
"""
Default table for object lists
"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BaseTable, self).__init__(*args, **kwargs) super(BaseTable, self).__init__(*args, **kwargs)
@ -18,6 +20,17 @@ class BaseTable(tables.Table):
} }
class SearchTable(tables.Table):
"""
Default table for search results
"""
class Meta:
attrs = {
'class': 'table table-hover',
}
orderable = False
class ToggleColumn(tables.CheckBoxColumn): class ToggleColumn(tables.CheckBoxColumn):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):