filters.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  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 NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
  12. from virtualization.models import Cluster
  13. from .constants import *
  14. from .models import (
  15. Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
  16. DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
  17. InventoryItem, Manufacturer, Platform, PowerFeed, PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort,
  18. PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
  19. VirtualChassis,
  20. )
  21. class RegionFilter(NameSlugSearchFilterSet):
  22. parent_id = django_filters.ModelMultipleChoiceFilter(
  23. queryset=Region.objects.all(),
  24. label='Parent region (ID)',
  25. )
  26. parent = django_filters.ModelMultipleChoiceFilter(
  27. field_name='parent__slug',
  28. queryset=Region.objects.all(),
  29. to_field_name='slug',
  30. label='Parent region (slug)',
  31. )
  32. class Meta:
  33. model = Region
  34. fields = ['id', 'name', 'slug']
  35. class SiteFilter(TenancyFilterSet, CustomFieldFilterSet):
  36. id__in = NumericInFilter(
  37. field_name='id',
  38. lookup_expr='in'
  39. )
  40. q = django_filters.CharFilter(
  41. method='search',
  42. label='Search',
  43. )
  44. status = django_filters.MultipleChoiceFilter(
  45. choices=SITE_STATUS_CHOICES,
  46. null_value=None
  47. )
  48. region_id = TreeNodeMultipleChoiceFilter(
  49. queryset=Region.objects.all(),
  50. field_name='region__in',
  51. label='Region (ID)',
  52. )
  53. region = TreeNodeMultipleChoiceFilter(
  54. queryset=Region.objects.all(),
  55. field_name='region__in',
  56. to_field_name='slug',
  57. label='Region (slug)',
  58. )
  59. tag = TagFilter()
  60. class Meta:
  61. model = Site
  62. fields = [
  63. 'id', 'name', 'slug', 'facility', 'asn', 'latitude', 'longitude', 'contact_name', 'contact_phone',
  64. 'contact_email',
  65. ]
  66. def search(self, queryset, name, value):
  67. if not value.strip():
  68. return queryset
  69. qs_filter = (
  70. Q(name__icontains=value) |
  71. Q(facility__icontains=value) |
  72. Q(description__icontains=value) |
  73. Q(physical_address__icontains=value) |
  74. Q(shipping_address__icontains=value) |
  75. Q(contact_name__icontains=value) |
  76. Q(contact_phone__icontains=value) |
  77. Q(contact_email__icontains=value) |
  78. Q(comments__icontains=value)
  79. )
  80. try:
  81. qs_filter |= Q(asn=int(value.strip()))
  82. except ValueError:
  83. pass
  84. return queryset.filter(qs_filter)
  85. class RackGroupFilter(NameSlugSearchFilterSet):
  86. site_id = django_filters.ModelMultipleChoiceFilter(
  87. queryset=Site.objects.all(),
  88. label='Site (ID)',
  89. )
  90. site = django_filters.ModelMultipleChoiceFilter(
  91. field_name='site__slug',
  92. queryset=Site.objects.all(),
  93. to_field_name='slug',
  94. label='Site (slug)',
  95. )
  96. class Meta:
  97. model = RackGroup
  98. fields = ['id', 'name', 'slug']
  99. class RackRoleFilter(NameSlugSearchFilterSet):
  100. class Meta:
  101. model = RackRole
  102. fields = ['id', 'name', 'slug', 'color']
  103. class RackFilter(TenancyFilterSet, CustomFieldFilterSet):
  104. id__in = NumericInFilter(
  105. field_name='id',
  106. lookup_expr='in'
  107. )
  108. q = django_filters.CharFilter(
  109. method='search',
  110. label='Search',
  111. )
  112. site_id = django_filters.ModelMultipleChoiceFilter(
  113. queryset=Site.objects.all(),
  114. label='Site (ID)',
  115. )
  116. site = django_filters.ModelMultipleChoiceFilter(
  117. field_name='site__slug',
  118. queryset=Site.objects.all(),
  119. to_field_name='slug',
  120. label='Site (slug)',
  121. )
  122. group_id = django_filters.ModelMultipleChoiceFilter(
  123. queryset=RackGroup.objects.all(),
  124. label='Group (ID)',
  125. )
  126. group = django_filters.ModelMultipleChoiceFilter(
  127. field_name='group__slug',
  128. queryset=RackGroup.objects.all(),
  129. to_field_name='slug',
  130. label='Group',
  131. )
  132. status = django_filters.MultipleChoiceFilter(
  133. choices=RACK_STATUS_CHOICES,
  134. null_value=None
  135. )
  136. role_id = django_filters.ModelMultipleChoiceFilter(
  137. queryset=RackRole.objects.all(),
  138. label='Role (ID)',
  139. )
  140. role = django_filters.ModelMultipleChoiceFilter(
  141. field_name='role__slug',
  142. queryset=RackRole.objects.all(),
  143. to_field_name='slug',
  144. label='Role (slug)',
  145. )
  146. tag = TagFilter()
  147. class Meta:
  148. model = Rack
  149. fields = [
  150. 'id', 'name', 'facility_id', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units',
  151. 'outer_width', 'outer_depth', '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 = ['id', '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 = ['id', 'name']
  307. class ConsoleServerPortTemplateFilter(DeviceTypeComponentFilterSet):
  308. class Meta:
  309. model = ConsoleServerPortTemplate
  310. fields = ['id', 'name']
  311. class PowerPortTemplateFilter(DeviceTypeComponentFilterSet):
  312. class Meta:
  313. model = PowerPortTemplate
  314. fields = ['id', 'name', 'maximum_draw', 'allocated_draw']
  315. class PowerOutletTemplateFilter(DeviceTypeComponentFilterSet):
  316. class Meta:
  317. model = PowerOutletTemplate
  318. fields = ['id', 'name', 'feed_leg']
  319. class InterfaceTemplateFilter(DeviceTypeComponentFilterSet):
  320. class Meta:
  321. model = InterfaceTemplate
  322. fields = ['id', 'name', 'type', 'mgmt_only']
  323. class FrontPortTemplateFilter(DeviceTypeComponentFilterSet):
  324. class Meta:
  325. model = FrontPortTemplate
  326. fields = ['id', 'name', 'type']
  327. class RearPortTemplateFilter(DeviceTypeComponentFilterSet):
  328. class Meta:
  329. model = RearPortTemplate
  330. fields = ['id', 'name', 'type', 'positions']
  331. class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
  332. class Meta:
  333. model = DeviceBayTemplate
  334. fields = ['id', 'name']
  335. class DeviceRoleFilter(NameSlugSearchFilterSet):
  336. class Meta:
  337. model = DeviceRole
  338. fields = ['id', '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 = ['id', 'name', 'slug', 'napalm_driver']
  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. region_id = TreeNodeMultipleChoiceFilter(
  400. queryset=Region.objects.all(),
  401. field_name='site__region__in',
  402. label='Region (ID)',
  403. )
  404. region = TreeNodeMultipleChoiceFilter(
  405. queryset=Region.objects.all(),
  406. field_name='site__region__in',
  407. to_field_name='slug',
  408. label='Region (slug)',
  409. )
  410. site_id = django_filters.ModelMultipleChoiceFilter(
  411. queryset=Site.objects.all(),
  412. label='Site (ID)',
  413. )
  414. site = django_filters.ModelMultipleChoiceFilter(
  415. field_name='site__slug',
  416. queryset=Site.objects.all(),
  417. to_field_name='slug',
  418. label='Site name (slug)',
  419. )
  420. rack_group_id = django_filters.ModelMultipleChoiceFilter(
  421. field_name='rack__group',
  422. queryset=RackGroup.objects.all(),
  423. label='Rack group (ID)',
  424. )
  425. rack_id = django_filters.ModelMultipleChoiceFilter(
  426. field_name='rack',
  427. queryset=Rack.objects.all(),
  428. label='Rack (ID)',
  429. )
  430. cluster_id = django_filters.ModelMultipleChoiceFilter(
  431. queryset=Cluster.objects.all(),
  432. label='VM cluster (ID)',
  433. )
  434. model = django_filters.ModelMultipleChoiceFilter(
  435. field_name='device_type__slug',
  436. queryset=DeviceType.objects.all(),
  437. to_field_name='slug',
  438. label='Device model (slug)',
  439. )
  440. status = django_filters.MultipleChoiceFilter(
  441. choices=DEVICE_STATUS_CHOICES,
  442. null_value=None
  443. )
  444. is_full_depth = django_filters.BooleanFilter(
  445. field_name='device_type__is_full_depth',
  446. label='Is full depth',
  447. )
  448. mac_address = django_filters.CharFilter(
  449. method='_mac_address',
  450. label='MAC address',
  451. )
  452. has_primary_ip = django_filters.BooleanFilter(
  453. method='_has_primary_ip',
  454. label='Has a primary IP',
  455. )
  456. virtual_chassis_id = django_filters.ModelMultipleChoiceFilter(
  457. field_name='virtual_chassis',
  458. queryset=VirtualChassis.objects.all(),
  459. label='Virtual chassis (ID)',
  460. )
  461. console_ports = django_filters.BooleanFilter(
  462. method='_console_ports',
  463. label='Has console ports',
  464. )
  465. console_server_ports = django_filters.BooleanFilter(
  466. method='_console_server_ports',
  467. label='Has console server ports',
  468. )
  469. power_ports = django_filters.BooleanFilter(
  470. method='_power_ports',
  471. label='Has power ports',
  472. )
  473. power_outlets = django_filters.BooleanFilter(
  474. method='_power_outlets',
  475. label='Has power outlets',
  476. )
  477. interfaces = django_filters.BooleanFilter(
  478. method='_interfaces',
  479. label='Has interfaces',
  480. )
  481. pass_through_ports = django_filters.BooleanFilter(
  482. method='_pass_through_ports',
  483. label='Has pass-through ports',
  484. )
  485. tag = TagFilter()
  486. class Meta:
  487. model = Device
  488. fields = ['id', 'name', 'serial', 'asset_tag', 'face', 'position', 'vc_position', 'vc_priority']
  489. def search(self, queryset, name, value):
  490. if not value.strip():
  491. return queryset
  492. return queryset.filter(
  493. Q(name__icontains=value) |
  494. Q(serial__icontains=value.strip()) |
  495. Q(inventory_items__serial__icontains=value.strip()) |
  496. Q(asset_tag__icontains=value.strip()) |
  497. Q(comments__icontains=value)
  498. ).distinct()
  499. def _mac_address(self, queryset, name, value):
  500. value = value.strip()
  501. if not value:
  502. return queryset
  503. try:
  504. mac = EUI(value.strip())
  505. return queryset.filter(interfaces__mac_address=mac).distinct()
  506. except AddrFormatError:
  507. return queryset.none()
  508. def _has_primary_ip(self, queryset, name, value):
  509. if value:
  510. return queryset.filter(
  511. Q(primary_ip4__isnull=False) |
  512. Q(primary_ip6__isnull=False)
  513. )
  514. else:
  515. return queryset.exclude(
  516. Q(primary_ip4__isnull=False) |
  517. Q(primary_ip6__isnull=False)
  518. )
  519. def _console_ports(self, queryset, name, value):
  520. return queryset.exclude(consoleports__isnull=value)
  521. def _console_server_ports(self, queryset, name, value):
  522. return queryset.exclude(consoleserverports__isnull=value)
  523. def _power_ports(self, queryset, name, value):
  524. return queryset.exclude(powerports__isnull=value)
  525. def _power_outlets(self, queryset, name, value):
  526. return queryset.exclude(poweroutlets__isnull=value)
  527. def _interfaces(self, queryset, name, value):
  528. return queryset.exclude(interfaces__isnull=value)
  529. def _pass_through_ports(self, queryset, name, value):
  530. return queryset.exclude(
  531. frontports__isnull=value,
  532. rearports__isnull=value
  533. )
  534. class DeviceComponentFilterSet(django_filters.FilterSet):
  535. q = django_filters.CharFilter(
  536. method='search',
  537. label='Search',
  538. )
  539. device_id = django_filters.ModelChoiceFilter(
  540. queryset=Device.objects.all(),
  541. label='Device (ID)',
  542. )
  543. device = django_filters.ModelChoiceFilter(
  544. queryset=Device.objects.all(),
  545. to_field_name='name',
  546. label='Device (name)',
  547. )
  548. tag = TagFilter()
  549. def search(self, queryset, name, value):
  550. if not value.strip():
  551. return queryset
  552. return queryset.filter(
  553. Q(name__icontains=value) |
  554. Q(description__icontains=value)
  555. )
  556. class ConsolePortFilter(DeviceComponentFilterSet):
  557. cabled = django_filters.BooleanFilter(
  558. field_name='cable',
  559. lookup_expr='isnull',
  560. exclude=True
  561. )
  562. class Meta:
  563. model = ConsolePort
  564. fields = ['id', 'name', 'description', 'connection_status']
  565. class ConsoleServerPortFilter(DeviceComponentFilterSet):
  566. cabled = django_filters.BooleanFilter(
  567. field_name='cable',
  568. lookup_expr='isnull',
  569. exclude=True
  570. )
  571. class Meta:
  572. model = ConsoleServerPort
  573. fields = ['id', 'name', 'description', 'connection_status']
  574. class PowerPortFilter(DeviceComponentFilterSet):
  575. cabled = django_filters.BooleanFilter(
  576. field_name='cable',
  577. lookup_expr='isnull',
  578. exclude=True
  579. )
  580. class Meta:
  581. model = PowerPort
  582. fields = ['id', 'name', 'maximum_draw', 'allocated_draw', 'description', 'connection_status']
  583. class PowerOutletFilter(DeviceComponentFilterSet):
  584. cabled = django_filters.BooleanFilter(
  585. field_name='cable',
  586. lookup_expr='isnull',
  587. exclude=True
  588. )
  589. class Meta:
  590. model = PowerOutlet
  591. fields = ['id', 'name', 'feed_leg', 'description', 'connection_status']
  592. class InterfaceFilter(django_filters.FilterSet):
  593. """
  594. Not using DeviceComponentFilterSet for Interfaces because we need to check for VirtualChassis membership.
  595. """
  596. q = django_filters.CharFilter(
  597. method='search',
  598. label='Search',
  599. )
  600. device = django_filters.CharFilter(
  601. method='filter_device',
  602. field_name='name',
  603. label='Device',
  604. )
  605. device_id = django_filters.NumberFilter(
  606. method='filter_device',
  607. field_name='pk',
  608. label='Device (ID)',
  609. )
  610. cabled = django_filters.BooleanFilter(
  611. field_name='cable',
  612. lookup_expr='isnull',
  613. exclude=True
  614. )
  615. kind = django_filters.CharFilter(
  616. method='filter_kind',
  617. label='Kind of interface',
  618. )
  619. lag_id = django_filters.ModelMultipleChoiceFilter(
  620. field_name='lag',
  621. queryset=Interface.objects.all(),
  622. label='LAG interface (ID)',
  623. )
  624. mac_address = django_filters.CharFilter(
  625. method='_mac_address',
  626. label='MAC address',
  627. )
  628. tag = TagFilter()
  629. vlan_id = django_filters.CharFilter(
  630. method='filter_vlan_id',
  631. label='Assigned VLAN'
  632. )
  633. vlan = django_filters.CharFilter(
  634. method='filter_vlan',
  635. label='Assigned VID'
  636. )
  637. type = django_filters.MultipleChoiceFilter(
  638. choices=IFACE_TYPE_CHOICES,
  639. null_value=None
  640. )
  641. class Meta:
  642. model = Interface
  643. fields = ['id', 'name', 'connection_status', 'type', 'enabled', 'mtu', 'mgmt_only', 'mode', 'description']
  644. def search(self, queryset, name, value):
  645. if not value.strip():
  646. return queryset
  647. return queryset.filter(
  648. Q(name__icontains=value) |
  649. Q(description__icontains=value)
  650. ).distinct()
  651. def filter_device(self, queryset, name, value):
  652. try:
  653. device = Device.objects.get(**{name: value})
  654. vc_interface_ids = device.vc_interfaces.values_list('id', flat=True)
  655. return queryset.filter(pk__in=vc_interface_ids)
  656. except Device.DoesNotExist:
  657. return queryset.none()
  658. def filter_vlan_id(self, queryset, name, value):
  659. value = value.strip()
  660. if not value:
  661. return queryset
  662. return queryset.filter(
  663. Q(untagged_vlan_id=value) |
  664. Q(tagged_vlans=value)
  665. )
  666. def filter_vlan(self, queryset, name, value):
  667. value = value.strip()
  668. if not value:
  669. return queryset
  670. return queryset.filter(
  671. Q(untagged_vlan_id__vid=value) |
  672. Q(tagged_vlans__vid=value)
  673. )
  674. def filter_kind(self, queryset, name, value):
  675. value = value.strip().lower()
  676. return {
  677. 'physical': queryset.exclude(type__in=NONCONNECTABLE_IFACE_TYPES),
  678. 'virtual': queryset.filter(type__in=VIRTUAL_IFACE_TYPES),
  679. 'wireless': queryset.filter(type__in=WIRELESS_IFACE_TYPES),
  680. }.get(value, queryset.none())
  681. def _mac_address(self, queryset, name, value):
  682. value = value.strip()
  683. if not value:
  684. return queryset
  685. try:
  686. mac = EUI(value.strip())
  687. return queryset.filter(mac_address=mac)
  688. except AddrFormatError:
  689. return queryset.none()
  690. class FrontPortFilter(DeviceComponentFilterSet):
  691. cabled = django_filters.BooleanFilter(
  692. field_name='cable',
  693. lookup_expr='isnull',
  694. exclude=True
  695. )
  696. class Meta:
  697. model = FrontPort
  698. fields = ['id', 'name', 'type', 'description']
  699. class RearPortFilter(DeviceComponentFilterSet):
  700. cabled = django_filters.BooleanFilter(
  701. field_name='cable',
  702. lookup_expr='isnull',
  703. exclude=True
  704. )
  705. class Meta:
  706. model = RearPort
  707. fields = ['id', 'name', 'type', 'positions', 'description']
  708. class DeviceBayFilter(DeviceComponentFilterSet):
  709. class Meta:
  710. model = DeviceBay
  711. fields = ['id', 'name', 'description']
  712. class InventoryItemFilter(DeviceComponentFilterSet):
  713. q = django_filters.CharFilter(
  714. method='search',
  715. label='Search',
  716. )
  717. device_id = django_filters.ModelChoiceFilter(
  718. queryset=Device.objects.all(),
  719. label='Device (ID)',
  720. )
  721. device = django_filters.ModelChoiceFilter(
  722. queryset=Device.objects.all(),
  723. to_field_name='name',
  724. label='Device (name)',
  725. )
  726. parent_id = django_filters.ModelMultipleChoiceFilter(
  727. queryset=InventoryItem.objects.all(),
  728. label='Parent inventory item (ID)',
  729. )
  730. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  731. queryset=Manufacturer.objects.all(),
  732. label='Manufacturer (ID)',
  733. )
  734. manufacturer = django_filters.ModelMultipleChoiceFilter(
  735. field_name='manufacturer__slug',
  736. queryset=Manufacturer.objects.all(),
  737. to_field_name='slug',
  738. label='Manufacturer (slug)',
  739. )
  740. class Meta:
  741. model = InventoryItem
  742. fields = ['id', 'name', 'part_id', 'serial', 'asset_tag', 'discovered']
  743. def search(self, queryset, name, value):
  744. if not value.strip():
  745. return queryset
  746. qs_filter = (
  747. Q(name__icontains=value) |
  748. Q(part_id__icontains=value) |
  749. Q(serial__iexact=value) |
  750. Q(asset_tag__iexact=value) |
  751. Q(description__icontains=value)
  752. )
  753. return queryset.filter(qs_filter)
  754. class VirtualChassisFilter(django_filters.FilterSet):
  755. q = django_filters.CharFilter(
  756. method='search',
  757. label='Search',
  758. )
  759. site_id = django_filters.ModelMultipleChoiceFilter(
  760. field_name='master__site',
  761. queryset=Site.objects.all(),
  762. label='Site (ID)',
  763. )
  764. site = django_filters.ModelMultipleChoiceFilter(
  765. field_name='master__site__slug',
  766. queryset=Site.objects.all(),
  767. to_field_name='slug',
  768. label='Site name (slug)',
  769. )
  770. tenant_id = django_filters.ModelMultipleChoiceFilter(
  771. field_name='master__tenant',
  772. queryset=Tenant.objects.all(),
  773. label='Tenant (ID)',
  774. )
  775. tenant = django_filters.ModelMultipleChoiceFilter(
  776. field_name='master__tenant__slug',
  777. queryset=Tenant.objects.all(),
  778. to_field_name='slug',
  779. label='Tenant (slug)',
  780. )
  781. tag = TagFilter()
  782. class Meta:
  783. model = VirtualChassis
  784. fields = ['id', 'domain']
  785. def search(self, queryset, name, value):
  786. if not value.strip():
  787. return queryset
  788. qs_filter = (
  789. Q(master__name__icontains=value) |
  790. Q(domain__icontains=value)
  791. )
  792. return queryset.filter(qs_filter)
  793. class CableFilter(django_filters.FilterSet):
  794. q = django_filters.CharFilter(
  795. method='search',
  796. label='Search',
  797. )
  798. type = django_filters.MultipleChoiceFilter(
  799. choices=CABLE_TYPE_CHOICES
  800. )
  801. status = django_filters.MultipleChoiceFilter(
  802. choices=CONNECTION_STATUS_CHOICES
  803. )
  804. color = django_filters.MultipleChoiceFilter(
  805. choices=COLOR_CHOICES
  806. )
  807. device = django_filters.CharFilter(
  808. method='filter_connected_device',
  809. field_name='name'
  810. )
  811. device_id = django_filters.CharFilter(
  812. method='filter_connected_device',
  813. field_name='pk'
  814. )
  815. class Meta:
  816. model = Cable
  817. fields = ['id', 'label', 'length', 'length_unit']
  818. def search(self, queryset, name, value):
  819. if not value.strip():
  820. return queryset
  821. return queryset.filter(label__icontains=value)
  822. def filter_connected_device(self, queryset, name, value):
  823. if not value.strip():
  824. return queryset
  825. try:
  826. device = Device.objects.get(**{name: value})
  827. except ObjectDoesNotExist:
  828. return queryset.none()
  829. cable_pks = device.get_cables(pk_list=True)
  830. return queryset.filter(pk__in=cable_pks)
  831. class ConsoleConnectionFilter(django_filters.FilterSet):
  832. site = django_filters.CharFilter(
  833. method='filter_site',
  834. label='Site (slug)',
  835. )
  836. device = django_filters.CharFilter(
  837. method='filter_device',
  838. label='Device',
  839. )
  840. class Meta:
  841. model = ConsolePort
  842. fields = ['name', 'connection_status']
  843. def filter_site(self, queryset, name, value):
  844. if not value.strip():
  845. return queryset
  846. return queryset.filter(connected_endpoint__device__site__slug=value)
  847. def filter_device(self, queryset, name, value):
  848. if not value.strip():
  849. return queryset
  850. return queryset.filter(
  851. Q(device__name__icontains=value) |
  852. Q(connected_endpoint__device__name__icontains=value)
  853. )
  854. class PowerConnectionFilter(django_filters.FilterSet):
  855. site = django_filters.CharFilter(
  856. method='filter_site',
  857. label='Site (slug)',
  858. )
  859. device = django_filters.CharFilter(
  860. method='filter_device',
  861. label='Device',
  862. )
  863. class Meta:
  864. model = PowerPort
  865. fields = ['name', 'connection_status']
  866. def filter_site(self, queryset, name, value):
  867. if not value.strip():
  868. return queryset
  869. return queryset.filter(_connected_poweroutlet__device__site__slug=value)
  870. def filter_device(self, queryset, name, value):
  871. if not value.strip():
  872. return queryset
  873. return queryset.filter(
  874. Q(device__name__icontains=value) |
  875. Q(_connected_poweroutlet__device__name__icontains=value)
  876. )
  877. class InterfaceConnectionFilter(django_filters.FilterSet):
  878. site = django_filters.CharFilter(
  879. method='filter_site',
  880. label='Site (slug)',
  881. )
  882. device = django_filters.CharFilter(
  883. method='filter_device',
  884. label='Device',
  885. )
  886. class Meta:
  887. model = Interface
  888. fields = ['connection_status']
  889. def filter_site(self, queryset, name, value):
  890. if not value.strip():
  891. return queryset
  892. return queryset.filter(
  893. Q(device__site__slug=value) |
  894. Q(_connected_interface__device__site__slug=value)
  895. )
  896. def filter_device(self, queryset, name, value):
  897. if not value.strip():
  898. return queryset
  899. return queryset.filter(
  900. Q(device__name__icontains=value) |
  901. Q(_connected_interface__device__name__icontains=value)
  902. )
  903. class PowerPanelFilter(django_filters.FilterSet):
  904. id__in = NumericInFilter(
  905. field_name='id',
  906. lookup_expr='in'
  907. )
  908. q = django_filters.CharFilter(
  909. method='search',
  910. label='Search',
  911. )
  912. site_id = django_filters.ModelMultipleChoiceFilter(
  913. queryset=Site.objects.all(),
  914. label='Site (ID)',
  915. )
  916. site = django_filters.ModelMultipleChoiceFilter(
  917. field_name='site__slug',
  918. queryset=Site.objects.all(),
  919. to_field_name='slug',
  920. label='Site name (slug)',
  921. )
  922. rack_group_id = django_filters.ModelMultipleChoiceFilter(
  923. field_name='rack_group',
  924. queryset=RackGroup.objects.all(),
  925. label='Rack group (ID)',
  926. )
  927. class Meta:
  928. model = PowerPanel
  929. fields = ['name']
  930. def search(self, queryset, name, value):
  931. if not value.strip():
  932. return queryset
  933. qs_filter = (
  934. Q(name__icontains=value)
  935. )
  936. return queryset.filter(qs_filter)
  937. class PowerFeedFilter(CustomFieldFilterSet):
  938. id__in = NumericInFilter(
  939. field_name='id',
  940. lookup_expr='in'
  941. )
  942. q = django_filters.CharFilter(
  943. method='search',
  944. label='Search',
  945. )
  946. site_id = django_filters.ModelMultipleChoiceFilter(
  947. field_name='power_panel__site',
  948. queryset=Site.objects.all(),
  949. label='Site (ID)',
  950. )
  951. site = django_filters.ModelMultipleChoiceFilter(
  952. field_name='power_panel__site__slug',
  953. queryset=Site.objects.all(),
  954. to_field_name='slug',
  955. label='Site name (slug)',
  956. )
  957. power_panel_id = django_filters.ModelMultipleChoiceFilter(
  958. queryset=PowerPanel.objects.all(),
  959. label='Power panel (ID)',
  960. )
  961. rack_id = django_filters.ModelMultipleChoiceFilter(
  962. field_name='rack',
  963. queryset=Rack.objects.all(),
  964. label='Rack (ID)',
  965. )
  966. tag = TagFilter()
  967. class Meta:
  968. model = PowerFeed
  969. fields = ['name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization']
  970. def search(self, queryset, name, value):
  971. if not value.strip():
  972. return queryset
  973. qs_filter = (
  974. Q(name__icontains=value) |
  975. Q(comments__icontains=value)
  976. )
  977. return queryset.filter(qs_filter)