filters.py 20 KB

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