filters.py 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. import django_filters
  2. from django.contrib.auth.models import User
  3. from django.core.exceptions import ObjectDoesNotExist
  4. from django.db.models import Q
  5. from netaddr import EUI
  6. from netaddr.core import AddrFormatError
  7. from extras.filters import CustomFieldFilterSet
  8. from tenancy.filtersets import TenancyFilterSet
  9. from tenancy.models import Tenant
  10. from utilities.constants import COLOR_CHOICES
  11. from utilities.filters import (
  12. NameSlugSearchFilterSet, NullableCharFieldFilter, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
  13. )
  14. from virtualization.models import Cluster
  15. from .constants import *
  16. from .models import (
  17. Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
  18. DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
  19. InventoryItem, Manufacturer, Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack,
  20. RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis,
  21. )
  22. class RegionFilter(NameSlugSearchFilterSet):
  23. parent_id = django_filters.ModelMultipleChoiceFilter(
  24. queryset=Region.objects.all(),
  25. label='Parent region (ID)',
  26. )
  27. parent = django_filters.ModelMultipleChoiceFilter(
  28. field_name='parent__slug',
  29. queryset=Region.objects.all(),
  30. to_field_name='slug',
  31. label='Parent region (slug)',
  32. )
  33. class Meta:
  34. model = Region
  35. fields = ['name', 'slug']
  36. class SiteFilter(TenancyFilterSet, CustomFieldFilterSet):
  37. id__in = NumericInFilter(
  38. field_name='id',
  39. lookup_expr='in'
  40. )
  41. q = django_filters.CharFilter(
  42. method='search',
  43. label='Search',
  44. )
  45. status = django_filters.MultipleChoiceFilter(
  46. choices=SITE_STATUS_CHOICES,
  47. null_value=None
  48. )
  49. region_id = TreeNodeMultipleChoiceFilter(
  50. queryset=Region.objects.all(),
  51. field_name='region__in',
  52. label='Region (ID)',
  53. )
  54. region = TreeNodeMultipleChoiceFilter(
  55. queryset=Region.objects.all(),
  56. field_name='region__in',
  57. to_field_name='slug',
  58. label='Region (slug)',
  59. )
  60. tag = TagFilter()
  61. class Meta:
  62. model = Site
  63. fields = ['q', 'name', 'slug', 'facility', 'asn', 'contact_name', 'contact_phone', 'contact_email']
  64. def search(self, queryset, name, value):
  65. if not value.strip():
  66. return queryset
  67. qs_filter = (
  68. Q(name__icontains=value) |
  69. Q(facility__icontains=value) |
  70. Q(description__icontains=value) |
  71. Q(physical_address__icontains=value) |
  72. Q(shipping_address__icontains=value) |
  73. Q(contact_name__icontains=value) |
  74. Q(contact_phone__icontains=value) |
  75. Q(contact_email__icontains=value) |
  76. Q(comments__icontains=value)
  77. )
  78. try:
  79. qs_filter |= Q(asn=int(value.strip()))
  80. except ValueError:
  81. pass
  82. return queryset.filter(qs_filter)
  83. class RackGroupFilter(NameSlugSearchFilterSet):
  84. site_id = django_filters.ModelMultipleChoiceFilter(
  85. queryset=Site.objects.all(),
  86. label='Site (ID)',
  87. )
  88. site = django_filters.ModelMultipleChoiceFilter(
  89. field_name='site__slug',
  90. queryset=Site.objects.all(),
  91. to_field_name='slug',
  92. label='Site (slug)',
  93. )
  94. class Meta:
  95. model = RackGroup
  96. fields = ['site_id', 'name', 'slug']
  97. class RackRoleFilter(NameSlugSearchFilterSet):
  98. class Meta:
  99. model = RackRole
  100. fields = ['name', 'slug', 'color']
  101. class RackFilter(TenancyFilterSet, CustomFieldFilterSet):
  102. id__in = NumericInFilter(
  103. field_name='id',
  104. lookup_expr='in'
  105. )
  106. q = django_filters.CharFilter(
  107. method='search',
  108. label='Search',
  109. )
  110. facility_id = NullableCharFieldFilter()
  111. site_id = django_filters.ModelMultipleChoiceFilter(
  112. queryset=Site.objects.all(),
  113. label='Site (ID)',
  114. )
  115. site = django_filters.ModelMultipleChoiceFilter(
  116. field_name='site__slug',
  117. queryset=Site.objects.all(),
  118. to_field_name='slug',
  119. label='Site (slug)',
  120. )
  121. group_id = django_filters.ModelMultipleChoiceFilter(
  122. queryset=RackGroup.objects.all(),
  123. label='Group (ID)',
  124. )
  125. group = django_filters.ModelMultipleChoiceFilter(
  126. field_name='group__slug',
  127. queryset=RackGroup.objects.all(),
  128. to_field_name='slug',
  129. label='Group',
  130. )
  131. status = django_filters.MultipleChoiceFilter(
  132. choices=RACK_STATUS_CHOICES,
  133. null_value=None
  134. )
  135. role_id = django_filters.ModelMultipleChoiceFilter(
  136. queryset=RackRole.objects.all(),
  137. label='Role (ID)',
  138. )
  139. role = django_filters.ModelMultipleChoiceFilter(
  140. field_name='role__slug',
  141. queryset=RackRole.objects.all(),
  142. to_field_name='slug',
  143. label='Role (slug)',
  144. )
  145. asset_tag = NullableCharFieldFilter()
  146. tag = TagFilter()
  147. class Meta:
  148. model = Rack
  149. fields = [
  150. 'name', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
  151. 'outer_unit',
  152. ]
  153. def search(self, queryset, name, value):
  154. if not value.strip():
  155. return queryset
  156. return queryset.filter(
  157. Q(name__icontains=value) |
  158. Q(facility_id__icontains=value) |
  159. Q(serial__icontains=value.strip()) |
  160. Q(asset_tag__icontains=value.strip()) |
  161. Q(comments__icontains=value)
  162. )
  163. class RackReservationFilter(TenancyFilterSet):
  164. id__in = NumericInFilter(
  165. field_name='id',
  166. lookup_expr='in'
  167. )
  168. q = django_filters.CharFilter(
  169. method='search',
  170. label='Search',
  171. )
  172. rack_id = django_filters.ModelMultipleChoiceFilter(
  173. queryset=Rack.objects.all(),
  174. label='Rack (ID)',
  175. )
  176. site_id = django_filters.ModelMultipleChoiceFilter(
  177. field_name='rack__site',
  178. queryset=Site.objects.all(),
  179. label='Site (ID)',
  180. )
  181. site = django_filters.ModelMultipleChoiceFilter(
  182. field_name='rack__site__slug',
  183. queryset=Site.objects.all(),
  184. to_field_name='slug',
  185. label='Site (slug)',
  186. )
  187. group_id = django_filters.ModelMultipleChoiceFilter(
  188. field_name='rack__group',
  189. queryset=RackGroup.objects.all(),
  190. label='Group (ID)',
  191. )
  192. group = django_filters.ModelMultipleChoiceFilter(
  193. field_name='rack__group__slug',
  194. queryset=RackGroup.objects.all(),
  195. to_field_name='slug',
  196. label='Group',
  197. )
  198. user_id = django_filters.ModelMultipleChoiceFilter(
  199. queryset=User.objects.all(),
  200. label='User (ID)',
  201. )
  202. user = django_filters.ModelMultipleChoiceFilter(
  203. field_name='user',
  204. queryset=User.objects.all(),
  205. to_field_name='username',
  206. label='User (name)',
  207. )
  208. class Meta:
  209. model = RackReservation
  210. fields = ['created']
  211. def search(self, queryset, name, value):
  212. if not value.strip():
  213. return queryset
  214. return queryset.filter(
  215. Q(rack__name__icontains=value) |
  216. Q(rack__facility_id__icontains=value) |
  217. Q(user__username__icontains=value) |
  218. Q(description__icontains=value)
  219. )
  220. class ManufacturerFilter(NameSlugSearchFilterSet):
  221. class Meta:
  222. model = Manufacturer
  223. fields = ['name', 'slug']
  224. class DeviceTypeFilter(CustomFieldFilterSet):
  225. id__in = NumericInFilter(
  226. field_name='id',
  227. lookup_expr='in'
  228. )
  229. q = django_filters.CharFilter(
  230. method='search',
  231. label='Search',
  232. )
  233. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  234. queryset=Manufacturer.objects.all(),
  235. label='Manufacturer (ID)',
  236. )
  237. manufacturer = django_filters.ModelMultipleChoiceFilter(
  238. field_name='manufacturer__slug',
  239. queryset=Manufacturer.objects.all(),
  240. to_field_name='slug',
  241. label='Manufacturer (slug)',
  242. )
  243. console_ports = django_filters.BooleanFilter(
  244. method='_console_ports',
  245. label='Has console ports',
  246. )
  247. console_server_ports = django_filters.BooleanFilter(
  248. method='_console_server_ports',
  249. label='Has console server ports',
  250. )
  251. power_ports = django_filters.BooleanFilter(
  252. method='_power_ports',
  253. label='Has power ports',
  254. )
  255. power_outlets = django_filters.BooleanFilter(
  256. method='_power_outlets',
  257. label='Has power outlets',
  258. )
  259. interfaces = django_filters.BooleanFilter(
  260. method='_interfaces',
  261. label='Has interfaces',
  262. )
  263. pass_through_ports = django_filters.BooleanFilter(
  264. method='_pass_through_ports',
  265. label='Has pass-through ports',
  266. )
  267. tag = TagFilter()
  268. class Meta:
  269. model = DeviceType
  270. fields = [
  271. 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
  272. ]
  273. def search(self, queryset, name, value):
  274. if not value.strip():
  275. return queryset
  276. return queryset.filter(
  277. Q(manufacturer__name__icontains=value) |
  278. Q(model__icontains=value) |
  279. Q(part_number__icontains=value) |
  280. Q(comments__icontains=value)
  281. )
  282. def _console_ports(self, queryset, name, value):
  283. return queryset.exclude(consoleport_templates__isnull=value)
  284. def _console_server_ports(self, queryset, name, value):
  285. return queryset.exclude(consoleserverport_templates__isnull=value)
  286. def _power_ports(self, queryset, name, value):
  287. return queryset.exclude(powerport_templates__isnull=value)
  288. def _power_outlets(self, queryset, name, value):
  289. return queryset.exclude(poweroutlet_templates__isnull=value)
  290. def _interfaces(self, queryset, name, value):
  291. return queryset.exclude(interface_templates__isnull=value)
  292. def _pass_through_ports(self, queryset, name, value):
  293. return queryset.exclude(
  294. frontport_templates__isnull=value,
  295. rearport_templates__isnull=value
  296. )
  297. class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet):
  298. devicetype_id = django_filters.ModelMultipleChoiceFilter(
  299. queryset=DeviceType.objects.all(),
  300. field_name='device_type_id',
  301. label='Device type (ID)',
  302. )
  303. class ConsolePortTemplateFilter(DeviceTypeComponentFilterSet):
  304. class Meta:
  305. model = ConsolePortTemplate
  306. fields = ['name']
  307. class ConsoleServerPortTemplateFilter(DeviceTypeComponentFilterSet):
  308. class Meta:
  309. model = ConsoleServerPortTemplate
  310. fields = ['name']
  311. class PowerPortTemplateFilter(DeviceTypeComponentFilterSet):
  312. class Meta:
  313. model = PowerPortTemplate
  314. fields = ['name']
  315. class PowerOutletTemplateFilter(DeviceTypeComponentFilterSet):
  316. class Meta:
  317. model = PowerOutletTemplate
  318. fields = ['name']
  319. class InterfaceTemplateFilter(DeviceTypeComponentFilterSet):
  320. class Meta:
  321. model = InterfaceTemplate
  322. fields = ['name', 'form_factor', 'mgmt_only']
  323. class FrontPortTemplateFilter(DeviceTypeComponentFilterSet):
  324. class Meta:
  325. model = FrontPortTemplate
  326. fields = ['name', 'type']
  327. class RearPortTemplateFilter(DeviceTypeComponentFilterSet):
  328. class Meta:
  329. model = RearPortTemplate
  330. fields = ['name', 'type']
  331. class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
  332. class Meta:
  333. model = DeviceBayTemplate
  334. fields = ['name']
  335. class DeviceRoleFilter(NameSlugSearchFilterSet):
  336. class Meta:
  337. model = DeviceRole
  338. fields = ['name', 'slug', 'color', 'vm_role']
  339. class PlatformFilter(NameSlugSearchFilterSet):
  340. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  341. field_name='manufacturer',
  342. queryset=Manufacturer.objects.all(),
  343. label='Manufacturer (ID)',
  344. )
  345. manufacturer = django_filters.ModelMultipleChoiceFilter(
  346. field_name='manufacturer__slug',
  347. queryset=Manufacturer.objects.all(),
  348. to_field_name='slug',
  349. label='Manufacturer (slug)',
  350. )
  351. class Meta:
  352. model = Platform
  353. fields = ['name', 'slug']
  354. class DeviceFilter(TenancyFilterSet, CustomFieldFilterSet):
  355. id__in = NumericInFilter(
  356. field_name='id',
  357. lookup_expr='in'
  358. )
  359. q = django_filters.CharFilter(
  360. method='search',
  361. label='Search',
  362. )
  363. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  364. field_name='device_type__manufacturer',
  365. queryset=Manufacturer.objects.all(),
  366. label='Manufacturer (ID)',
  367. )
  368. manufacturer = django_filters.ModelMultipleChoiceFilter(
  369. field_name='device_type__manufacturer__slug',
  370. queryset=Manufacturer.objects.all(),
  371. to_field_name='slug',
  372. label='Manufacturer (slug)',
  373. )
  374. device_type_id = django_filters.ModelMultipleChoiceFilter(
  375. queryset=DeviceType.objects.all(),
  376. label='Device type (ID)',
  377. )
  378. role_id = django_filters.ModelMultipleChoiceFilter(
  379. field_name='device_role_id',
  380. queryset=DeviceRole.objects.all(),
  381. label='Role (ID)',
  382. )
  383. role = django_filters.ModelMultipleChoiceFilter(
  384. field_name='device_role__slug',
  385. queryset=DeviceRole.objects.all(),
  386. to_field_name='slug',
  387. label='Role (slug)',
  388. )
  389. platform_id = django_filters.ModelMultipleChoiceFilter(
  390. queryset=Platform.objects.all(),
  391. label='Platform (ID)',
  392. )
  393. platform = django_filters.ModelMultipleChoiceFilter(
  394. field_name='platform__slug',
  395. queryset=Platform.objects.all(),
  396. to_field_name='slug',
  397. label='Platform (slug)',
  398. )
  399. name = NullableCharFieldFilter()
  400. asset_tag = NullableCharFieldFilter()
  401. region_id = TreeNodeMultipleChoiceFilter(
  402. queryset=Region.objects.all(),
  403. field_name='site__region__in',
  404. label='Region (ID)',
  405. )
  406. region = TreeNodeMultipleChoiceFilter(
  407. queryset=Region.objects.all(),
  408. field_name='site__region__in',
  409. to_field_name='slug',
  410. label='Region (slug)',
  411. )
  412. site_id = django_filters.ModelMultipleChoiceFilter(
  413. queryset=Site.objects.all(),
  414. label='Site (ID)',
  415. )
  416. site = django_filters.ModelMultipleChoiceFilter(
  417. field_name='site__slug',
  418. queryset=Site.objects.all(),
  419. to_field_name='slug',
  420. label='Site name (slug)',
  421. )
  422. rack_group_id = django_filters.ModelMultipleChoiceFilter(
  423. field_name='rack__group',
  424. queryset=RackGroup.objects.all(),
  425. label='Rack group (ID)',
  426. )
  427. rack_id = django_filters.ModelMultipleChoiceFilter(
  428. field_name='rack',
  429. queryset=Rack.objects.all(),
  430. label='Rack (ID)',
  431. )
  432. position = django_filters.ChoiceFilter(
  433. choices=DEVICE_POSITION_CHOICES,
  434. null_label='Non-racked'
  435. )
  436. cluster_id = django_filters.ModelMultipleChoiceFilter(
  437. queryset=Cluster.objects.all(),
  438. label='VM cluster (ID)',
  439. )
  440. model = django_filters.ModelMultipleChoiceFilter(
  441. field_name='device_type__slug',
  442. queryset=DeviceType.objects.all(),
  443. to_field_name='slug',
  444. label='Device model (slug)',
  445. )
  446. status = django_filters.MultipleChoiceFilter(
  447. choices=DEVICE_STATUS_CHOICES,
  448. null_value=None
  449. )
  450. is_full_depth = django_filters.BooleanFilter(
  451. field_name='device_type__is_full_depth',
  452. label='Is full depth',
  453. )
  454. mac_address = django_filters.CharFilter(
  455. method='_mac_address',
  456. label='MAC address',
  457. )
  458. has_primary_ip = django_filters.BooleanFilter(
  459. method='_has_primary_ip',
  460. label='Has a primary IP',
  461. )
  462. virtual_chassis_id = django_filters.ModelMultipleChoiceFilter(
  463. field_name='virtual_chassis',
  464. queryset=VirtualChassis.objects.all(),
  465. label='Virtual chassis (ID)',
  466. )
  467. console_ports = django_filters.BooleanFilter(
  468. method='_console_ports',
  469. label='Has console ports',
  470. )
  471. console_server_ports = django_filters.BooleanFilter(
  472. method='_console_server_ports',
  473. label='Has console server ports',
  474. )
  475. power_ports = django_filters.BooleanFilter(
  476. method='_power_ports',
  477. label='Has power ports',
  478. )
  479. power_outlets = django_filters.BooleanFilter(
  480. method='_power_outlets',
  481. label='Has power outlets',
  482. )
  483. interfaces = django_filters.BooleanFilter(
  484. method='_interfaces',
  485. label='Has interfaces',
  486. )
  487. pass_through_ports = django_filters.BooleanFilter(
  488. method='_pass_through_ports',
  489. label='Has pass-through ports',
  490. )
  491. tag = TagFilter()
  492. class Meta:
  493. model = Device
  494. fields = ['serial', 'face']
  495. def search(self, queryset, name, value):
  496. if not value.strip():
  497. return queryset
  498. return queryset.filter(
  499. Q(name__icontains=value) |
  500. Q(serial__icontains=value.strip()) |
  501. Q(inventory_items__serial__icontains=value.strip()) |
  502. Q(asset_tag__icontains=value.strip()) |
  503. Q(comments__icontains=value)
  504. ).distinct()
  505. def _mac_address(self, queryset, name, value):
  506. value = value.strip()
  507. if not value:
  508. return queryset
  509. try:
  510. mac = EUI(value.strip())
  511. return queryset.filter(interfaces__mac_address=mac).distinct()
  512. except AddrFormatError:
  513. return queryset.none()
  514. def _has_primary_ip(self, queryset, name, value):
  515. if value:
  516. return queryset.filter(
  517. Q(primary_ip4__isnull=False) |
  518. Q(primary_ip6__isnull=False)
  519. )
  520. else:
  521. return queryset.exclude(
  522. Q(primary_ip4__isnull=False) |
  523. Q(primary_ip6__isnull=False)
  524. )
  525. def _console_ports(self, queryset, name, value):
  526. return queryset.exclude(consoleports__isnull=value)
  527. def _console_server_ports(self, queryset, name, value):
  528. return queryset.exclude(consoleserverports__isnull=value)
  529. def _power_ports(self, queryset, name, value):
  530. return queryset.exclude(powerports__isnull=value)
  531. def _power_outlets(self, queryset, name, value):
  532. return queryset.exclude(poweroutlets_isnull=value)
  533. def _interfaces(self, queryset, name, value):
  534. return queryset.exclude(interfaces__isnull=value)
  535. def _pass_through_ports(self, queryset, name, value):
  536. return queryset.exclude(
  537. frontports__isnull=value,
  538. rearports__isnull=value
  539. )
  540. class DeviceComponentFilterSet(django_filters.FilterSet):
  541. q = django_filters.CharFilter(
  542. method='search',
  543. label='Search',
  544. )
  545. device_id = django_filters.ModelChoiceFilter(
  546. queryset=Device.objects.all(),
  547. label='Device (ID)',
  548. )
  549. device = django_filters.ModelChoiceFilter(
  550. queryset=Device.objects.all(),
  551. to_field_name='name',
  552. label='Device (name)',
  553. )
  554. tag = TagFilter()
  555. def search(self, queryset, name, value):
  556. if not value.strip():
  557. return queryset
  558. return queryset.filter(
  559. Q(name__icontains=value)
  560. )
  561. class ConsolePortFilter(DeviceComponentFilterSet):
  562. cabled = django_filters.BooleanFilter(
  563. field_name='cable',
  564. lookup_expr='isnull',
  565. exclude=True
  566. )
  567. class Meta:
  568. model = ConsolePort
  569. fields = ['name', 'connection_status']
  570. class ConsoleServerPortFilter(DeviceComponentFilterSet):
  571. cabled = django_filters.BooleanFilter(
  572. field_name='cable',
  573. lookup_expr='isnull',
  574. exclude=True
  575. )
  576. class Meta:
  577. model = ConsoleServerPort
  578. fields = ['name', 'connection_status']
  579. class PowerPortFilter(DeviceComponentFilterSet):
  580. cabled = django_filters.BooleanFilter(
  581. field_name='cable',
  582. lookup_expr='isnull',
  583. exclude=True
  584. )
  585. class Meta:
  586. model = PowerPort
  587. fields = ['name', 'connection_status']
  588. class PowerOutletFilter(DeviceComponentFilterSet):
  589. cabled = django_filters.BooleanFilter(
  590. field_name='cable',
  591. lookup_expr='isnull',
  592. exclude=True
  593. )
  594. class Meta:
  595. model = PowerOutlet
  596. fields = ['name', 'connection_status']
  597. class InterfaceFilter(django_filters.FilterSet):
  598. """
  599. Not using DeviceComponentFilterSet for Interfaces because we need to check for VirtualChassis membership.
  600. """
  601. q = django_filters.CharFilter(
  602. method='search',
  603. label='Search',
  604. )
  605. device = django_filters.CharFilter(
  606. method='filter_device',
  607. field_name='name',
  608. label='Device',
  609. )
  610. device_id = django_filters.NumberFilter(
  611. method='filter_device',
  612. field_name='pk',
  613. label='Device (ID)',
  614. )
  615. cabled = django_filters.BooleanFilter(
  616. field_name='cable',
  617. lookup_expr='isnull',
  618. exclude=True
  619. )
  620. type = django_filters.CharFilter(
  621. method='filter_type',
  622. label='Interface type',
  623. )
  624. lag_id = django_filters.ModelMultipleChoiceFilter(
  625. field_name='lag',
  626. queryset=Interface.objects.all(),
  627. label='LAG interface (ID)',
  628. )
  629. mac_address = django_filters.CharFilter(
  630. method='_mac_address',
  631. label='MAC address',
  632. )
  633. tag = TagFilter()
  634. vlan_id = django_filters.CharFilter(
  635. method='filter_vlan_id',
  636. label='Assigned VLAN'
  637. )
  638. vlan = django_filters.CharFilter(
  639. method='filter_vlan',
  640. label='Assigned VID'
  641. )
  642. form_factor = django_filters.MultipleChoiceFilter(
  643. choices=IFACE_FF_CHOICES,
  644. null_value=None
  645. )
  646. class Meta:
  647. model = Interface
  648. fields = ['name', 'connection_status', 'form_factor', 'enabled', 'mtu', 'mgmt_only']
  649. def search(self, queryset, name, value):
  650. if not value.strip():
  651. return queryset
  652. return queryset.filter(
  653. Q(name__icontains=value)
  654. ).distinct()
  655. def filter_device(self, queryset, name, value):
  656. try:
  657. device = Device.objects.get(**{name: value})
  658. vc_interface_ids = device.vc_interfaces.values_list('id', flat=True)
  659. return queryset.filter(pk__in=vc_interface_ids)
  660. except Device.DoesNotExist:
  661. return queryset.none()
  662. def filter_vlan_id(self, queryset, name, value):
  663. value = value.strip()
  664. if not value:
  665. return queryset
  666. return queryset.filter(
  667. Q(untagged_vlan_id=value) |
  668. Q(tagged_vlans=value)
  669. )
  670. def filter_vlan(self, queryset, name, value):
  671. value = value.strip()
  672. if not value:
  673. return queryset
  674. return queryset.filter(
  675. Q(untagged_vlan_id__vid=value) |
  676. Q(tagged_vlans__vid=value)
  677. )
  678. def filter_type(self, queryset, name, value):
  679. value = value.strip().lower()
  680. return {
  681. 'physical': queryset.exclude(form_factor__in=NONCONNECTABLE_IFACE_TYPES),
  682. 'virtual': queryset.filter(form_factor__in=VIRTUAL_IFACE_TYPES),
  683. 'wireless': queryset.filter(form_factor__in=WIRELESS_IFACE_TYPES),
  684. 'lag': queryset.filter(form_factor=IFACE_FF_LAG),
  685. }.get(value, queryset.none())
  686. def _mac_address(self, queryset, name, value):
  687. value = value.strip()
  688. if not value:
  689. return queryset
  690. try:
  691. mac = EUI(value.strip())
  692. return queryset.filter(mac_address=mac)
  693. except AddrFormatError:
  694. return queryset.none()
  695. class FrontPortFilter(DeviceComponentFilterSet):
  696. cabled = django_filters.BooleanFilter(
  697. field_name='cable',
  698. lookup_expr='isnull',
  699. exclude=True
  700. )
  701. class Meta:
  702. model = FrontPort
  703. fields = ['name', 'type']
  704. class RearPortFilter(DeviceComponentFilterSet):
  705. cabled = django_filters.BooleanFilter(
  706. field_name='cable',
  707. lookup_expr='isnull',
  708. exclude=True
  709. )
  710. class Meta:
  711. model = RearPort
  712. fields = ['name', 'type']
  713. class DeviceBayFilter(DeviceComponentFilterSet):
  714. class Meta:
  715. model = DeviceBay
  716. fields = ['name']
  717. class InventoryItemFilter(DeviceComponentFilterSet):
  718. q = django_filters.CharFilter(
  719. method='search',
  720. label='Search',
  721. )
  722. device_id = django_filters.ModelChoiceFilter(
  723. queryset=Device.objects.all(),
  724. label='Device (ID)',
  725. )
  726. device = django_filters.ModelChoiceFilter(
  727. queryset=Device.objects.all(),
  728. to_field_name='name',
  729. label='Device (name)',
  730. )
  731. parent_id = django_filters.ModelMultipleChoiceFilter(
  732. queryset=InventoryItem.objects.all(),
  733. label='Parent inventory item (ID)',
  734. )
  735. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  736. queryset=Manufacturer.objects.all(),
  737. label='Manufacturer (ID)',
  738. )
  739. manufacturer = django_filters.ModelMultipleChoiceFilter(
  740. field_name='manufacturer__slug',
  741. queryset=Manufacturer.objects.all(),
  742. to_field_name='slug',
  743. label='Manufacturer (slug)',
  744. )
  745. asset_tag = NullableCharFieldFilter()
  746. class Meta:
  747. model = InventoryItem
  748. fields = ['name', 'part_id', 'serial', 'asset_tag', 'discovered']
  749. def search(self, queryset, name, value):
  750. if not value.strip():
  751. return queryset
  752. qs_filter = (
  753. Q(name__icontains=value) |
  754. Q(part_id__icontains=value) |
  755. Q(serial__iexact=value) |
  756. Q(asset_tag__iexact=value) |
  757. Q(description__icontains=value)
  758. )
  759. return queryset.filter(qs_filter)
  760. class VirtualChassisFilter(django_filters.FilterSet):
  761. q = django_filters.CharFilter(
  762. method='search',
  763. label='Search',
  764. )
  765. site_id = django_filters.ModelMultipleChoiceFilter(
  766. field_name='master__site',
  767. queryset=Site.objects.all(),
  768. label='Site (ID)',
  769. )
  770. site = django_filters.ModelMultipleChoiceFilter(
  771. field_name='master__site__slug',
  772. queryset=Site.objects.all(),
  773. to_field_name='slug',
  774. label='Site name (slug)',
  775. )
  776. tenant_id = django_filters.ModelMultipleChoiceFilter(
  777. field_name='master__tenant',
  778. queryset=Tenant.objects.all(),
  779. label='Tenant (ID)',
  780. )
  781. tenant = django_filters.ModelMultipleChoiceFilter(
  782. field_name='master__tenant__slug',
  783. queryset=Tenant.objects.all(),
  784. to_field_name='slug',
  785. label='Tenant (slug)',
  786. )
  787. tag = TagFilter()
  788. class Meta:
  789. model = VirtualChassis
  790. fields = ['domain']
  791. def search(self, queryset, name, value):
  792. if not value.strip():
  793. return queryset
  794. qs_filter = (
  795. Q(master__name__icontains=value) |
  796. Q(domain__icontains=value)
  797. )
  798. return queryset.filter(qs_filter)
  799. class CableFilter(django_filters.FilterSet):
  800. q = django_filters.CharFilter(
  801. method='search',
  802. label='Search',
  803. )
  804. type = django_filters.MultipleChoiceFilter(
  805. choices=CABLE_TYPE_CHOICES
  806. )
  807. color = django_filters.MultipleChoiceFilter(
  808. choices=COLOR_CHOICES
  809. )
  810. device = django_filters.CharFilter(
  811. method='filter_connected_device',
  812. field_name='name'
  813. )
  814. device_id = django_filters.CharFilter(
  815. method='filter_connected_device',
  816. field_name='pk'
  817. )
  818. class Meta:
  819. model = Cable
  820. fields = ['type', 'status', 'color', 'length', 'length_unit']
  821. def search(self, queryset, name, value):
  822. if not value.strip():
  823. return queryset
  824. return queryset.filter(label__icontains=value)
  825. def filter_connected_device(self, queryset, name, value):
  826. if not value.strip():
  827. return queryset
  828. try:
  829. device = Device.objects.get(**{name: value})
  830. except ObjectDoesNotExist:
  831. return queryset.none()
  832. cable_pks = device.get_cables(pk_list=True)
  833. return queryset.filter(pk__in=cable_pks)
  834. class ConsoleConnectionFilter(django_filters.FilterSet):
  835. site = django_filters.CharFilter(
  836. method='filter_site',
  837. label='Site (slug)',
  838. )
  839. device = django_filters.CharFilter(
  840. method='filter_device',
  841. label='Device',
  842. )
  843. class Meta:
  844. model = ConsolePort
  845. fields = ['name', 'connection_status']
  846. def filter_site(self, queryset, name, value):
  847. if not value.strip():
  848. return queryset
  849. return queryset.filter(connected_endpoint__device__site__slug=value)
  850. def filter_device(self, queryset, name, value):
  851. if not value.strip():
  852. return queryset
  853. return queryset.filter(
  854. Q(device__name__icontains=value) |
  855. Q(connected_endpoint__device__name__icontains=value)
  856. )
  857. class PowerConnectionFilter(django_filters.FilterSet):
  858. site = django_filters.CharFilter(
  859. method='filter_site',
  860. label='Site (slug)',
  861. )
  862. device = django_filters.CharFilter(
  863. method='filter_device',
  864. label='Device',
  865. )
  866. class Meta:
  867. model = PowerPort
  868. fields = ['name', 'connection_status']
  869. def filter_site(self, queryset, name, value):
  870. if not value.strip():
  871. return queryset
  872. return queryset.filter(connected_endpoint__device__site__slug=value)
  873. def filter_device(self, queryset, name, value):
  874. if not value.strip():
  875. return queryset
  876. return queryset.filter(
  877. Q(device__name__icontains=value) |
  878. Q(connected_endpoint__device__name__icontains=value)
  879. )
  880. class InterfaceConnectionFilter(django_filters.FilterSet):
  881. site = django_filters.CharFilter(
  882. method='filter_site',
  883. label='Site (slug)',
  884. )
  885. device = django_filters.CharFilter(
  886. method='filter_device',
  887. label='Device',
  888. )
  889. class Meta:
  890. model = Interface
  891. fields = ['connection_status']
  892. def filter_site(self, queryset, name, value):
  893. if not value.strip():
  894. return queryset
  895. return queryset.filter(
  896. Q(device__site__slug=value) |
  897. Q(_connected_interface__device__site__slug=value)
  898. )
  899. def filter_device(self, queryset, name, value):
  900. if not value.strip():
  901. return queryset
  902. return queryset.filter(
  903. Q(device__name__icontains=value) |
  904. Q(_connected_interface__device__name__icontains=value)
  905. )