filters.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. from __future__ import unicode_literals
  2. import django_filters
  3. from netaddr.core import AddrFormatError
  4. from django.db.models import Q
  5. from extras.filters import CustomFieldFilterSet
  6. from tenancy.models import Tenant
  7. from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
  8. from .models import (
  9. ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
  10. DeviceBayTemplate, DeviceRole, DeviceType, STATUS_CHOICES, IFACE_FF_LAG, Interface, InterfaceConnection,
  11. InterfaceTemplate, Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort,
  12. PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, Region, Site, VIRTUAL_IFACE_TYPES,
  13. )
  14. class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet):
  15. id__in = NumericInFilter(name='id', lookup_expr='in')
  16. q = django_filters.CharFilter(
  17. method='search',
  18. label='Search',
  19. )
  20. region_id = NullableModelMultipleChoiceFilter(
  21. name='region',
  22. queryset=Region.objects.all(),
  23. label='Region (ID)',
  24. )
  25. region = NullableModelMultipleChoiceFilter(
  26. name='region',
  27. queryset=Region.objects.all(),
  28. to_field_name='slug',
  29. label='Region (slug)',
  30. )
  31. tenant_id = NullableModelMultipleChoiceFilter(
  32. name='tenant',
  33. queryset=Tenant.objects.all(),
  34. label='Tenant (ID)',
  35. )
  36. tenant = NullableModelMultipleChoiceFilter(
  37. name='tenant',
  38. queryset=Tenant.objects.all(),
  39. to_field_name='slug',
  40. label='Tenant (slug)',
  41. )
  42. class Meta:
  43. model = Site
  44. fields = ['q', 'name', 'facility', 'asn']
  45. def search(self, queryset, name, value):
  46. if not value.strip():
  47. return queryset
  48. qs_filter = (
  49. Q(name__icontains=value) |
  50. Q(facility__icontains=value) |
  51. Q(physical_address__icontains=value) |
  52. Q(shipping_address__icontains=value) |
  53. Q(comments__icontains=value)
  54. )
  55. try:
  56. qs_filter |= Q(asn=int(value.strip()))
  57. except ValueError:
  58. pass
  59. return queryset.filter(qs_filter)
  60. class RackGroupFilter(django_filters.FilterSet):
  61. site_id = django_filters.ModelMultipleChoiceFilter(
  62. name='site',
  63. queryset=Site.objects.all(),
  64. label='Site (ID)',
  65. )
  66. site = django_filters.ModelMultipleChoiceFilter(
  67. name='site__slug',
  68. queryset=Site.objects.all(),
  69. to_field_name='slug',
  70. label='Site (slug)',
  71. )
  72. class Meta:
  73. model = RackGroup
  74. fields = ['name']
  75. class RackFilter(CustomFieldFilterSet, django_filters.FilterSet):
  76. id__in = NumericInFilter(name='id', lookup_expr='in')
  77. q = django_filters.CharFilter(
  78. method='search',
  79. label='Search',
  80. )
  81. site_id = django_filters.ModelMultipleChoiceFilter(
  82. name='site',
  83. queryset=Site.objects.all(),
  84. label='Site (ID)',
  85. )
  86. site = django_filters.ModelMultipleChoiceFilter(
  87. name='site__slug',
  88. queryset=Site.objects.all(),
  89. to_field_name='slug',
  90. label='Site (slug)',
  91. )
  92. group_id = NullableModelMultipleChoiceFilter(
  93. name='group',
  94. queryset=RackGroup.objects.all(),
  95. label='Group (ID)',
  96. )
  97. group = NullableModelMultipleChoiceFilter(
  98. name='group',
  99. queryset=RackGroup.objects.all(),
  100. to_field_name='slug',
  101. label='Group',
  102. )
  103. tenant_id = NullableModelMultipleChoiceFilter(
  104. name='tenant',
  105. queryset=Tenant.objects.all(),
  106. label='Tenant (ID)',
  107. )
  108. tenant = NullableModelMultipleChoiceFilter(
  109. name='tenant',
  110. queryset=Tenant.objects.all(),
  111. to_field_name='slug',
  112. label='Tenant (slug)',
  113. )
  114. role_id = NullableModelMultipleChoiceFilter(
  115. name='role',
  116. queryset=RackRole.objects.all(),
  117. label='Role (ID)',
  118. )
  119. role = NullableModelMultipleChoiceFilter(
  120. name='role',
  121. queryset=RackRole.objects.all(),
  122. to_field_name='slug',
  123. label='Role (slug)',
  124. )
  125. class Meta:
  126. model = Rack
  127. fields = ['u_height']
  128. def search(self, queryset, name, value):
  129. if not value.strip():
  130. return queryset
  131. return queryset.filter(
  132. Q(name__icontains=value) |
  133. Q(facility_id__icontains=value) |
  134. Q(comments__icontains=value)
  135. )
  136. class RackReservationFilter(django_filters.FilterSet):
  137. id__in = NumericInFilter(name='id', lookup_expr='in')
  138. q = django_filters.CharFilter(
  139. method='search',
  140. label='Search',
  141. )
  142. site_id = django_filters.ModelMultipleChoiceFilter(
  143. name='rack__site',
  144. queryset=Site.objects.all(),
  145. label='Site (ID)',
  146. )
  147. site = django_filters.ModelMultipleChoiceFilter(
  148. name='rack__site__slug',
  149. queryset=Site.objects.all(),
  150. to_field_name='slug',
  151. label='Site (slug)',
  152. )
  153. group_id = NullableModelMultipleChoiceFilter(
  154. name='rack__group',
  155. queryset=RackGroup.objects.all(),
  156. label='Group (ID)',
  157. )
  158. group = NullableModelMultipleChoiceFilter(
  159. name='rack__group',
  160. queryset=RackGroup.objects.all(),
  161. to_field_name='slug',
  162. label='Group',
  163. )
  164. rack_id = django_filters.ModelMultipleChoiceFilter(
  165. name='rack',
  166. queryset=Rack.objects.all(),
  167. label='Rack (ID)',
  168. )
  169. class Meta:
  170. model = RackReservation
  171. fields = ['rack', 'user']
  172. def search(self, queryset, name, value):
  173. if not value.strip():
  174. return queryset
  175. return queryset.filter(
  176. Q(rack__name__icontains=value) |
  177. Q(rack__facility_id__icontains=value) |
  178. Q(user__username__icontains=value) |
  179. Q(description__icontains=value)
  180. )
  181. class DeviceTypeFilter(CustomFieldFilterSet, django_filters.FilterSet):
  182. id__in = NumericInFilter(name='id', lookup_expr='in')
  183. q = django_filters.CharFilter(
  184. method='search',
  185. label='Search',
  186. )
  187. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  188. name='manufacturer',
  189. queryset=Manufacturer.objects.all(),
  190. label='Manufacturer (ID)',
  191. )
  192. manufacturer = django_filters.ModelMultipleChoiceFilter(
  193. name='manufacturer__slug',
  194. queryset=Manufacturer.objects.all(),
  195. to_field_name='slug',
  196. label='Manufacturer (slug)',
  197. )
  198. class Meta:
  199. model = DeviceType
  200. fields = [
  201. 'model', 'part_number', 'u_height', 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role',
  202. ]
  203. def search(self, queryset, name, value):
  204. if not value.strip():
  205. return queryset
  206. return queryset.filter(
  207. Q(manufacturer__name__icontains=value) |
  208. Q(model__icontains=value) |
  209. Q(part_number__icontains=value) |
  210. Q(comments__icontains=value)
  211. )
  212. class DeviceTypeComponentFilterSet(django_filters.FilterSet):
  213. devicetype_id = django_filters.ModelMultipleChoiceFilter(
  214. name='device_type',
  215. queryset=DeviceType.objects.all(),
  216. label='Device type (ID)',
  217. )
  218. devicetype = django_filters.ModelMultipleChoiceFilter(
  219. name='device_type',
  220. queryset=DeviceType.objects.all(),
  221. to_field_name='name',
  222. label='Device type (name)',
  223. )
  224. class ConsolePortTemplateFilter(DeviceTypeComponentFilterSet):
  225. class Meta:
  226. model = ConsolePortTemplate
  227. fields = ['name']
  228. class ConsoleServerPortTemplateFilter(DeviceTypeComponentFilterSet):
  229. class Meta:
  230. model = ConsoleServerPortTemplate
  231. fields = ['name']
  232. class PowerPortTemplateFilter(DeviceTypeComponentFilterSet):
  233. class Meta:
  234. model = PowerPortTemplate
  235. fields = ['name']
  236. class PowerOutletTemplateFilter(DeviceTypeComponentFilterSet):
  237. class Meta:
  238. model = PowerOutletTemplate
  239. fields = ['name']
  240. class InterfaceTemplateFilter(DeviceTypeComponentFilterSet):
  241. class Meta:
  242. model = InterfaceTemplate
  243. fields = ['name', 'form_factor']
  244. class DeviceBayTemplateFilter(DeviceTypeComponentFilterSet):
  245. class Meta:
  246. model = DeviceBayTemplate
  247. fields = ['name']
  248. class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet):
  249. id__in = NumericInFilter(name='id', lookup_expr='in')
  250. q = django_filters.CharFilter(
  251. method='search',
  252. label='Search',
  253. )
  254. mac_address = django_filters.CharFilter(
  255. method='_mac_address',
  256. label='MAC address',
  257. )
  258. site_id = django_filters.ModelMultipleChoiceFilter(
  259. name='site',
  260. queryset=Site.objects.all(),
  261. label='Site (ID)',
  262. )
  263. site = django_filters.ModelMultipleChoiceFilter(
  264. name='site__slug',
  265. queryset=Site.objects.all(),
  266. to_field_name='slug',
  267. label='Site name (slug)',
  268. )
  269. rack_group_id = django_filters.ModelMultipleChoiceFilter(
  270. name='rack__group',
  271. queryset=RackGroup.objects.all(),
  272. label='Rack group (ID)',
  273. )
  274. rack_id = NullableModelMultipleChoiceFilter(
  275. name='rack',
  276. queryset=Rack.objects.all(),
  277. label='Rack (ID)',
  278. )
  279. role_id = django_filters.ModelMultipleChoiceFilter(
  280. name='device_role',
  281. queryset=DeviceRole.objects.all(),
  282. label='Role (ID)',
  283. )
  284. role = django_filters.ModelMultipleChoiceFilter(
  285. name='device_role__slug',
  286. queryset=DeviceRole.objects.all(),
  287. to_field_name='slug',
  288. label='Role (slug)',
  289. )
  290. tenant_id = NullableModelMultipleChoiceFilter(
  291. name='tenant',
  292. queryset=Tenant.objects.all(),
  293. label='Tenant (ID)',
  294. )
  295. tenant = NullableModelMultipleChoiceFilter(
  296. name='tenant',
  297. queryset=Tenant.objects.all(),
  298. to_field_name='slug',
  299. label='Tenant (slug)',
  300. )
  301. device_type_id = django_filters.ModelMultipleChoiceFilter(
  302. name='device_type',
  303. queryset=DeviceType.objects.all(),
  304. label='Device type (ID)',
  305. )
  306. manufacturer_id = django_filters.ModelMultipleChoiceFilter(
  307. name='device_type__manufacturer',
  308. queryset=Manufacturer.objects.all(),
  309. label='Manufacturer (ID)',
  310. )
  311. manufacturer = django_filters.ModelMultipleChoiceFilter(
  312. name='device_type__manufacturer__slug',
  313. queryset=Manufacturer.objects.all(),
  314. to_field_name='slug',
  315. label='Manufacturer (slug)',
  316. )
  317. model = django_filters.ModelMultipleChoiceFilter(
  318. name='device_type__slug',
  319. queryset=DeviceType.objects.all(),
  320. to_field_name='slug',
  321. label='Device model (slug)',
  322. )
  323. platform_id = NullableModelMultipleChoiceFilter(
  324. name='platform',
  325. queryset=Platform.objects.all(),
  326. label='Platform (ID)',
  327. )
  328. platform = NullableModelMultipleChoiceFilter(
  329. name='platform',
  330. queryset=Platform.objects.all(),
  331. to_field_name='slug',
  332. label='Platform (slug)',
  333. )
  334. is_console_server = django_filters.BooleanFilter(
  335. name='device_type__is_console_server',
  336. label='Is a console server',
  337. )
  338. is_pdu = django_filters.BooleanFilter(
  339. name='device_type__is_pdu',
  340. label='Is a PDU',
  341. )
  342. is_network_device = django_filters.BooleanFilter(
  343. name='device_type__is_network_device',
  344. label='Is a network device',
  345. )
  346. has_primary_ip = django_filters.BooleanFilter(
  347. method='_has_primary_ip',
  348. label='Has a primary IP',
  349. )
  350. status = django_filters.MultipleChoiceFilter(
  351. choices=STATUS_CHOICES
  352. )
  353. class Meta:
  354. model = Device
  355. fields = ['name', 'serial', 'asset_tag']
  356. def search(self, queryset, name, value):
  357. if not value.strip():
  358. return queryset
  359. return queryset.filter(
  360. Q(name__icontains=value) |
  361. Q(serial__icontains=value.strip()) |
  362. Q(inventory_items__serial__icontains=value.strip()) |
  363. Q(asset_tag=value.strip()) |
  364. Q(comments__icontains=value)
  365. ).distinct()
  366. def _mac_address(self, queryset, name, value):
  367. value = value.strip()
  368. if not value:
  369. return queryset
  370. try:
  371. return queryset.filter(interfaces__mac_address=value).distinct()
  372. except AddrFormatError:
  373. return queryset.none()
  374. def _has_primary_ip(self, queryset, name, value):
  375. if value:
  376. return queryset.filter(
  377. Q(primary_ip4__isnull=False) |
  378. Q(primary_ip6__isnull=False)
  379. )
  380. else:
  381. return queryset.exclude(
  382. Q(primary_ip4__isnull=False) |
  383. Q(primary_ip6__isnull=False)
  384. )
  385. class DeviceComponentFilterSet(django_filters.FilterSet):
  386. device_id = django_filters.ModelChoiceFilter(
  387. name='device',
  388. queryset=Device.objects.all(),
  389. label='Device (ID)',
  390. )
  391. device = django_filters.ModelChoiceFilter(
  392. name='device__name',
  393. queryset=Device.objects.all(),
  394. to_field_name='name',
  395. label='Device (name)',
  396. )
  397. class ConsolePortFilter(DeviceComponentFilterSet):
  398. class Meta:
  399. model = ConsolePort
  400. fields = ['name']
  401. class ConsoleServerPortFilter(DeviceComponentFilterSet):
  402. class Meta:
  403. model = ConsoleServerPort
  404. fields = ['name']
  405. class PowerPortFilter(DeviceComponentFilterSet):
  406. class Meta:
  407. model = PowerPort
  408. fields = ['name']
  409. class PowerOutletFilter(DeviceComponentFilterSet):
  410. class Meta:
  411. model = PowerOutlet
  412. fields = ['name']
  413. class InterfaceFilter(django_filters.FilterSet):
  414. device = django_filters.CharFilter(
  415. method='filter_device',
  416. name='name',
  417. label='Device',
  418. )
  419. device_id = django_filters.NumberFilter(
  420. method='filter_device',
  421. name='pk',
  422. label='Device (ID)',
  423. )
  424. type = django_filters.CharFilter(
  425. method='filter_type',
  426. label='Interface type',
  427. )
  428. lag_id = django_filters.ModelMultipleChoiceFilter(
  429. name='lag',
  430. queryset=Interface.objects.all(),
  431. label='LAG interface (ID)',
  432. )
  433. mac_address = django_filters.CharFilter(
  434. method='_mac_address',
  435. label='MAC address',
  436. )
  437. class Meta:
  438. model = Interface
  439. fields = ['name', 'form_factor']
  440. def filter_device(self, queryset, name, value):
  441. try:
  442. device = Device.objects.select_related('device_type').get(**{name: value})
  443. ordering = device.device_type.interface_ordering
  444. return queryset.filter(device=device).order_naturally(ordering)
  445. except Device.DoesNotExist:
  446. return queryset.none()
  447. def filter_type(self, queryset, name, value):
  448. value = value.strip().lower()
  449. if value == 'physical':
  450. return queryset.exclude(form_factor__in=VIRTUAL_IFACE_TYPES)
  451. elif value == 'virtual':
  452. return queryset.filter(form_factor__in=VIRTUAL_IFACE_TYPES)
  453. elif value == 'lag':
  454. return queryset.filter(form_factor=IFACE_FF_LAG)
  455. return queryset
  456. def _mac_address(self, queryset, name, value):
  457. value = value.strip()
  458. if not value:
  459. return queryset
  460. try:
  461. return queryset.filter(mac_address=value)
  462. except AddrFormatError:
  463. return queryset.none()
  464. class DeviceBayFilter(DeviceComponentFilterSet):
  465. class Meta:
  466. model = DeviceBay
  467. fields = ['name']
  468. class InventoryItemFilter(DeviceComponentFilterSet):
  469. class Meta:
  470. model = InventoryItem
  471. fields = ['name']
  472. class ConsoleConnectionFilter(django_filters.FilterSet):
  473. site = django_filters.CharFilter(
  474. method='filter_site',
  475. label='Site (slug)',
  476. )
  477. device = django_filters.CharFilter(
  478. method='filter_device',
  479. label='Device',
  480. )
  481. class Meta:
  482. model = ConsolePort
  483. fields = ['name', 'connection_status']
  484. def filter_site(self, queryset, name, value):
  485. if not value.strip():
  486. return queryset
  487. return queryset.filter(cs_port__device__site__slug=value)
  488. def filter_device(self, queryset, name, value):
  489. if not value.strip():
  490. return queryset
  491. return queryset.filter(
  492. Q(device__name__icontains=value) |
  493. Q(cs_port__device__name__icontains=value)
  494. )
  495. class PowerConnectionFilter(django_filters.FilterSet):
  496. site = django_filters.CharFilter(
  497. method='filter_site',
  498. label='Site (slug)',
  499. )
  500. device = django_filters.CharFilter(
  501. method='filter_device',
  502. label='Device',
  503. )
  504. class Meta:
  505. model = PowerPort
  506. fields = ['name', 'connection_status']
  507. def filter_site(self, queryset, name, value):
  508. if not value.strip():
  509. return queryset
  510. return queryset.filter(power_outlet__device__site__slug=value)
  511. def filter_device(self, queryset, name, value):
  512. if not value.strip():
  513. return queryset
  514. return queryset.filter(
  515. Q(device__name__icontains=value) |
  516. Q(power_outlet__device__name__icontains=value)
  517. )
  518. class InterfaceConnectionFilter(django_filters.FilterSet):
  519. site = django_filters.CharFilter(
  520. method='filter_site',
  521. label='Site (slug)',
  522. )
  523. device = django_filters.CharFilter(
  524. method='filter_device',
  525. label='Device',
  526. )
  527. class Meta:
  528. model = InterfaceConnection
  529. fields = ['connection_status']
  530. def filter_site(self, queryset, name, value):
  531. if not value.strip():
  532. return queryset
  533. return queryset.filter(
  534. Q(interface_a__device__site__slug=value) |
  535. Q(interface_b__device__site__slug=value)
  536. )
  537. def filter_device(self, queryset, name, value):
  538. if not value.strip():
  539. return queryset
  540. return queryset.filter(
  541. Q(interface_a__device__name__icontains=value) |
  542. Q(interface_b__device__name__icontains=value)
  543. )