devices.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. import django_tables2 as tables
  2. from django_tables2.utils import Accessor
  3. from django.conf import settings
  4. from dcim.models import (
  5. ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, FrontPort, Interface, InventoryItem, Platform,
  6. PowerOutlet, PowerPort, RearPort, VirtualChassis,
  7. )
  8. from tenancy.tables import COL_TENANT
  9. from utilities.tables import (
  10. BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
  11. TagColumn, ToggleColumn,
  12. )
  13. from .template_code import (
  14. CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
  15. FRONTPORT_BUTTONS, INTERFACE_BUTTONS, INTERFACE_IPADDRESSES, INTERFACE_TAGGED_VLANS, POWEROUTLET_BUTTONS,
  16. POWERPORT_BUTTONS, REARPORT_BUTTONS,
  17. )
  18. __all__ = (
  19. 'ConsolePortTable',
  20. 'ConsoleServerPortTable',
  21. 'DeviceBayTable',
  22. 'DeviceConsolePortTable',
  23. 'DeviceConsoleServerPortTable',
  24. 'DeviceDeviceBayTable',
  25. 'DeviceFrontPortTable',
  26. 'DeviceImportTable',
  27. 'DeviceInterfaceTable',
  28. 'DeviceInventoryItemTable',
  29. 'DevicePowerPortTable',
  30. 'DevicePowerOutletTable',
  31. 'DeviceRearPortTable',
  32. 'DeviceRoleTable',
  33. 'DeviceTable',
  34. 'FrontPortTable',
  35. 'InterfaceTable',
  36. 'InventoryItemTable',
  37. 'PlatformTable',
  38. 'PowerOutletTable',
  39. 'PowerPortTable',
  40. 'RearPortTable',
  41. 'VirtualChassisTable',
  42. )
  43. #
  44. # Device roles
  45. #
  46. class DeviceRoleTable(BaseTable):
  47. pk = ToggleColumn()
  48. device_count = LinkedCountColumn(
  49. viewname='dcim:device_list',
  50. url_params={'role': 'slug'},
  51. verbose_name='Devices'
  52. )
  53. vm_count = LinkedCountColumn(
  54. viewname='virtualization:virtualmachine_list',
  55. url_params={'role': 'slug'},
  56. verbose_name='VMs'
  57. )
  58. color = ColorColumn()
  59. vm_role = BooleanColumn()
  60. actions = ButtonsColumn(DeviceRole, pk_field='slug')
  61. class Meta(BaseTable.Meta):
  62. model = DeviceRole
  63. fields = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'actions')
  64. default_columns = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'actions')
  65. #
  66. # Platforms
  67. #
  68. class PlatformTable(BaseTable):
  69. pk = ToggleColumn()
  70. device_count = LinkedCountColumn(
  71. viewname='dcim:device_list',
  72. url_params={'platform': 'slug'},
  73. verbose_name='Devices'
  74. )
  75. vm_count = LinkedCountColumn(
  76. viewname='virtualization:virtualmachine_list',
  77. url_params={'platform': 'slug'},
  78. verbose_name='VMs'
  79. )
  80. actions = ButtonsColumn(Platform, pk_field='slug')
  81. class Meta(BaseTable.Meta):
  82. model = Platform
  83. fields = (
  84. 'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args',
  85. 'description', 'actions',
  86. )
  87. default_columns = (
  88. 'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'napalm_driver', 'description', 'actions',
  89. )
  90. #
  91. # Devices
  92. #
  93. class DeviceTable(BaseTable):
  94. pk = ToggleColumn()
  95. name = tables.TemplateColumn(
  96. order_by=('_name',),
  97. template_code=DEVICE_LINK
  98. )
  99. status = ChoiceFieldColumn()
  100. tenant = tables.TemplateColumn(
  101. template_code=COL_TENANT
  102. )
  103. site = tables.Column(
  104. linkify=True
  105. )
  106. rack = tables.Column(
  107. linkify=True
  108. )
  109. device_role = ColoredLabelColumn(
  110. verbose_name='Role'
  111. )
  112. device_type = tables.LinkColumn(
  113. viewname='dcim:devicetype',
  114. args=[Accessor('device_type__pk')],
  115. verbose_name='Type',
  116. text=lambda record: record.device_type.display_name
  117. )
  118. if settings.PREFER_IPV4:
  119. primary_ip = tables.Column(
  120. linkify=True,
  121. order_by=('primary_ip4', 'primary_ip6'),
  122. verbose_name='IP Address'
  123. )
  124. else:
  125. primary_ip = tables.Column(
  126. linkify=True,
  127. order_by=('primary_ip6', 'primary_ip4'),
  128. verbose_name='IP Address'
  129. )
  130. primary_ip4 = tables.Column(
  131. linkify=True,
  132. verbose_name='IPv4 Address'
  133. )
  134. primary_ip6 = tables.Column(
  135. linkify=True,
  136. verbose_name='IPv6 Address'
  137. )
  138. cluster = tables.LinkColumn(
  139. viewname='virtualization:cluster',
  140. args=[Accessor('cluster__pk')]
  141. )
  142. virtual_chassis = tables.LinkColumn(
  143. viewname='dcim:virtualchassis',
  144. args=[Accessor('virtual_chassis__pk')]
  145. )
  146. vc_position = tables.Column(
  147. verbose_name='VC Position'
  148. )
  149. vc_priority = tables.Column(
  150. verbose_name='VC Priority'
  151. )
  152. tags = TagColumn(
  153. url_name='dcim:device_list'
  154. )
  155. class Meta(BaseTable.Meta):
  156. model = Device
  157. fields = (
  158. 'pk', 'name', 'status', 'tenant', 'device_role', 'device_type', 'platform', 'serial', 'asset_tag', 'site',
  159. 'rack', 'position', 'face', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis',
  160. 'vc_position', 'vc_priority', 'tags',
  161. )
  162. default_columns = (
  163. 'pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip',
  164. )
  165. class DeviceImportTable(BaseTable):
  166. name = tables.TemplateColumn(
  167. template_code=DEVICE_LINK
  168. )
  169. status = ChoiceFieldColumn()
  170. tenant = tables.TemplateColumn(
  171. template_code=COL_TENANT
  172. )
  173. site = tables.Column(
  174. linkify=True
  175. )
  176. rack = tables.Column(
  177. linkify=True
  178. )
  179. device_role = tables.Column(
  180. verbose_name='Role'
  181. )
  182. device_type = tables.Column(
  183. verbose_name='Type'
  184. )
  185. class Meta(BaseTable.Meta):
  186. model = Device
  187. fields = ('name', 'status', 'tenant', 'site', 'rack', 'position', 'device_role', 'device_type')
  188. empty_text = False
  189. #
  190. # Device components
  191. #
  192. class DeviceComponentTable(BaseTable):
  193. pk = ToggleColumn()
  194. device = tables.Column(
  195. linkify=True
  196. )
  197. name = tables.Column(
  198. linkify=True,
  199. order_by=('_name',)
  200. )
  201. cable = tables.Column(
  202. linkify=True
  203. )
  204. class Meta(BaseTable.Meta):
  205. order_by = ('device', 'name')
  206. class CableTerminationTable(BaseTable):
  207. cable = tables.Column(
  208. linkify=True
  209. )
  210. cable_peer = tables.TemplateColumn(
  211. accessor='_cable_peer',
  212. template_code=CABLETERMINATION,
  213. orderable=False,
  214. verbose_name='Cable Peer'
  215. )
  216. class PathEndpointTable(CableTerminationTable):
  217. connection = tables.TemplateColumn(
  218. accessor='_path.destination',
  219. template_code=CABLETERMINATION,
  220. verbose_name='Connection',
  221. orderable=False
  222. )
  223. class ConsolePortTable(DeviceComponentTable, PathEndpointTable):
  224. tags = TagColumn(
  225. url_name='dcim:consoleport_list'
  226. )
  227. class Meta(DeviceComponentTable.Meta):
  228. model = ConsolePort
  229. fields = (
  230. 'pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags',
  231. )
  232. default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
  233. class DeviceConsolePortTable(ConsolePortTable):
  234. name = tables.TemplateColumn(
  235. template_code='<i class="mdi mdi-console"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  236. attrs={'td': {'class': 'text-nowrap'}}
  237. )
  238. actions = ButtonsColumn(
  239. model=ConsolePort,
  240. buttons=('edit', 'delete'),
  241. prepend_template=CONSOLEPORT_BUTTONS
  242. )
  243. class Meta(DeviceComponentTable.Meta):
  244. model = ConsolePort
  245. fields = (
  246. 'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
  247. )
  248. default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
  249. row_attrs = {
  250. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  251. }
  252. class ConsoleServerPortTable(DeviceComponentTable, PathEndpointTable):
  253. tags = TagColumn(
  254. url_name='dcim:consoleserverport_list'
  255. )
  256. class Meta(DeviceComponentTable.Meta):
  257. model = ConsoleServerPort
  258. fields = ('pk', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags')
  259. default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
  260. class DeviceConsoleServerPortTable(ConsoleServerPortTable):
  261. name = tables.TemplateColumn(
  262. template_code='<i class="mdi mdi-console-network-outline"></i> '
  263. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  264. attrs={'td': {'class': 'text-nowrap'}}
  265. )
  266. actions = ButtonsColumn(
  267. model=ConsoleServerPort,
  268. buttons=('edit', 'delete'),
  269. prepend_template=CONSOLESERVERPORT_BUTTONS
  270. )
  271. class Meta(DeviceComponentTable.Meta):
  272. model = ConsoleServerPort
  273. fields = (
  274. 'pk', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'connection', 'tags', 'actions'
  275. )
  276. default_columns = ('pk', 'name', 'label', 'type', 'description', 'cable', 'connection', 'actions')
  277. row_attrs = {
  278. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  279. }
  280. class PowerPortTable(DeviceComponentTable, PathEndpointTable):
  281. tags = TagColumn(
  282. url_name='dcim:powerport_list'
  283. )
  284. class Meta(DeviceComponentTable.Meta):
  285. model = PowerPort
  286. fields = (
  287. 'pk', 'device', 'name', 'label', 'type', 'description', 'maximum_draw', 'allocated_draw', 'cable',
  288. 'cable_peer', 'connection', 'tags',
  289. )
  290. default_columns = ('pk', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
  291. class DevicePowerPortTable(PowerPortTable):
  292. name = tables.TemplateColumn(
  293. template_code='<i class="mdi mdi-power-plug-outline"></i> <a href="{{ record.get_absolute_url }}">'
  294. '{{ value }}</a>',
  295. attrs={'td': {'class': 'text-nowrap'}}
  296. )
  297. actions = ButtonsColumn(
  298. model=PowerPort,
  299. buttons=('edit', 'delete'),
  300. prepend_template=POWERPORT_BUTTONS
  301. )
  302. class Meta(DeviceComponentTable.Meta):
  303. model = PowerPort
  304. fields = (
  305. 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'cable_peer',
  306. 'connection', 'tags', 'actions',
  307. )
  308. default_columns = (
  309. 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'connection',
  310. 'actions',
  311. )
  312. row_attrs = {
  313. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  314. }
  315. class PowerOutletTable(DeviceComponentTable, PathEndpointTable):
  316. power_port = tables.Column(
  317. linkify=True
  318. )
  319. tags = TagColumn(
  320. url_name='dcim:poweroutlet_list'
  321. )
  322. class Meta(DeviceComponentTable.Meta):
  323. model = PowerOutlet
  324. fields = (
  325. 'pk', 'device', 'name', 'label', 'type', 'description', 'power_port', 'feed_leg', 'cable', 'cable_peer',
  326. 'connection', 'tags',
  327. )
  328. default_columns = ('pk', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description')
  329. class DevicePowerOutletTable(PowerOutletTable):
  330. name = tables.TemplateColumn(
  331. template_code='<i class="mdi mdi-power-socket"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  332. attrs={'td': {'class': 'text-nowrap'}}
  333. )
  334. actions = ButtonsColumn(
  335. model=PowerOutlet,
  336. buttons=('edit', 'delete'),
  337. prepend_template=POWEROUTLET_BUTTONS
  338. )
  339. class Meta(DeviceComponentTable.Meta):
  340. model = PowerOutlet
  341. fields = (
  342. 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'cable_peer', 'connection',
  343. 'tags', 'actions',
  344. )
  345. default_columns = (
  346. 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'connection', 'actions',
  347. )
  348. row_attrs = {
  349. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  350. }
  351. class BaseInterfaceTable(BaseTable):
  352. enabled = BooleanColumn()
  353. ip_addresses = tables.TemplateColumn(
  354. template_code=INTERFACE_IPADDRESSES,
  355. orderable=False,
  356. verbose_name='IP Addresses'
  357. )
  358. untagged_vlan = tables.Column(linkify=True)
  359. tagged_vlans = tables.TemplateColumn(
  360. template_code=INTERFACE_TAGGED_VLANS,
  361. orderable=False,
  362. verbose_name='Tagged VLANs'
  363. )
  364. class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable):
  365. mgmt_only = BooleanColumn()
  366. tags = TagColumn(
  367. url_name='dcim:interface_list'
  368. )
  369. class Meta(DeviceComponentTable.Meta):
  370. model = Interface
  371. fields = (
  372. 'pk', 'device', 'name', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address',
  373. 'description', 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
  374. )
  375. default_columns = ('pk', 'device', 'name', 'label', 'enabled', 'type', 'description')
  376. class DeviceInterfaceTable(InterfaceTable):
  377. name = tables.TemplateColumn(
  378. template_code='<i class="mdi mdi-{% if iface.mgmt_only %}wrench{% elif iface.is_lag %}drag-horizontal-variant'
  379. '{% elif iface.is_virtual %}circle{% elif iface.is_wireless %}wifi{% else %}ethernet'
  380. '{% endif %}"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  381. attrs={'td': {'class': 'text-nowrap'}}
  382. )
  383. lag = tables.Column(
  384. linkify=True,
  385. verbose_name='LAG'
  386. )
  387. actions = ButtonsColumn(
  388. model=Interface,
  389. buttons=('edit', 'delete'),
  390. prepend_template=INTERFACE_BUTTONS
  391. )
  392. class Meta(DeviceComponentTable.Meta):
  393. model = Interface
  394. fields = (
  395. 'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'description',
  396. 'cable', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans', 'actions',
  397. )
  398. default_columns = (
  399. 'pk', 'name', 'label', 'enabled', 'type', 'lag', 'mtu', 'mode', 'description', 'ip_addresses', 'cable',
  400. 'connection', 'actions',
  401. )
  402. row_attrs = {
  403. 'class': lambda record: record.cable.get_status_class() if record.cable else '',
  404. 'data-name': lambda record: record.name,
  405. }
  406. class FrontPortTable(DeviceComponentTable, CableTerminationTable):
  407. rear_port_position = tables.Column(
  408. verbose_name='Position'
  409. )
  410. rear_port = tables.Column(
  411. linkify=True
  412. )
  413. tags = TagColumn(
  414. url_name='dcim:frontport_list'
  415. )
  416. class Meta(DeviceComponentTable.Meta):
  417. model = FrontPort
  418. fields = (
  419. 'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable',
  420. 'cable_peer', 'tags',
  421. )
  422. default_columns = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description')
  423. class DeviceFrontPortTable(FrontPortTable):
  424. name = tables.TemplateColumn(
  425. template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
  426. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  427. attrs={'td': {'class': 'text-nowrap'}}
  428. )
  429. actions = ButtonsColumn(
  430. model=FrontPort,
  431. buttons=('edit', 'delete'),
  432. prepend_template=FRONTPORT_BUTTONS
  433. )
  434. class Meta(DeviceComponentTable.Meta):
  435. model = FrontPort
  436. fields = (
  437. 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
  438. 'tags', 'actions',
  439. )
  440. default_columns = (
  441. 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
  442. 'actions',
  443. )
  444. row_attrs = {
  445. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  446. }
  447. class RearPortTable(DeviceComponentTable, CableTerminationTable):
  448. tags = TagColumn(
  449. url_name='dcim:rearport_list'
  450. )
  451. class Meta(DeviceComponentTable.Meta):
  452. model = RearPort
  453. fields = ('pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags')
  454. default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
  455. class DeviceRearPortTable(RearPortTable):
  456. name = tables.TemplateColumn(
  457. template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
  458. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  459. attrs={'td': {'class': 'text-nowrap'}}
  460. )
  461. actions = ButtonsColumn(
  462. model=RearPort,
  463. buttons=('edit', 'delete'),
  464. prepend_template=REARPORT_BUTTONS
  465. )
  466. class Meta(DeviceComponentTable.Meta):
  467. model = RearPort
  468. fields = (
  469. 'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'tags', 'actions',
  470. )
  471. default_columns = (
  472. 'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'actions',
  473. )
  474. row_attrs = {
  475. 'class': lambda record: record.cable.get_status_class() if record.cable else ''
  476. }
  477. class DeviceBayTable(DeviceComponentTable):
  478. status = tables.TemplateColumn(
  479. template_code=DEVICEBAY_STATUS
  480. )
  481. installed_device = tables.Column(
  482. linkify=True
  483. )
  484. tags = TagColumn(
  485. url_name='dcim:devicebay_list'
  486. )
  487. class Meta(DeviceComponentTable.Meta):
  488. model = DeviceBay
  489. fields = ('pk', 'device', 'name', 'label', 'status', 'installed_device', 'description', 'tags')
  490. default_columns = ('pk', 'device', 'name', 'label', 'status', 'installed_device', 'description')
  491. class DeviceDeviceBayTable(DeviceBayTable):
  492. name = tables.TemplateColumn(
  493. template_code='<i class="mdi mdi-circle{% if record.installed_device %}slice-8{% else %}outline{% endif %}'
  494. '"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  495. attrs={'td': {'class': 'text-nowrap'}}
  496. )
  497. actions = ButtonsColumn(
  498. model=DeviceBay,
  499. buttons=('edit', 'delete'),
  500. prepend_template=DEVICEBAY_BUTTONS
  501. )
  502. class Meta(DeviceComponentTable.Meta):
  503. model = DeviceBay
  504. fields = (
  505. 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions',
  506. )
  507. default_columns = (
  508. 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'actions',
  509. )
  510. class InventoryItemTable(DeviceComponentTable):
  511. manufacturer = tables.Column(
  512. linkify=True
  513. )
  514. discovered = BooleanColumn()
  515. tags = TagColumn(
  516. url_name='dcim:inventoryitem_list'
  517. )
  518. cable = None # Override DeviceComponentTable
  519. class Meta(DeviceComponentTable.Meta):
  520. model = InventoryItem
  521. fields = (
  522. 'pk', 'device', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description',
  523. 'discovered', 'tags',
  524. )
  525. default_columns = ('pk', 'device', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag')
  526. class DeviceInventoryItemTable(InventoryItemTable):
  527. name = tables.TemplateColumn(
  528. template_code='<a href="{{ record.get_absolute_url }}" style="padding-left: {{ record.level }}0px">'
  529. '{{ value }}</a>',
  530. attrs={'td': {'class': 'text-nowrap'}}
  531. )
  532. actions = ButtonsColumn(
  533. model=InventoryItem,
  534. buttons=('edit', 'delete')
  535. )
  536. class Meta(DeviceComponentTable.Meta):
  537. model = InventoryItem
  538. fields = (
  539. 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
  540. 'tags', 'actions',
  541. )
  542. default_columns = (
  543. 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
  544. 'actions',
  545. )
  546. #
  547. # Virtual chassis
  548. #
  549. class VirtualChassisTable(BaseTable):
  550. pk = ToggleColumn()
  551. name = tables.Column(
  552. linkify=True
  553. )
  554. master = tables.Column(
  555. linkify=True
  556. )
  557. member_count = LinkedCountColumn(
  558. viewname='dcim:device_list',
  559. url_params={'virtual_chassis_id': 'pk'},
  560. verbose_name='Members'
  561. )
  562. tags = TagColumn(
  563. url_name='dcim:virtualchassis_list'
  564. )
  565. class Meta(BaseTable.Meta):
  566. model = VirtualChassis
  567. fields = ('pk', 'name', 'domain', 'master', 'member_count', 'tags')
  568. default_columns = ('pk', 'name', 'domain', 'master', 'member_count')