filtersets.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. import django_filters
  2. import netaddr
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.core.exceptions import ValidationError
  5. from django.db.models import Q
  6. from netaddr.core import AddrFormatError
  7. from dcim.models import Device, Interface, Region, Site, SiteGroup
  8. from extras.filters import TagFilter
  9. from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
  10. from tenancy.filtersets import TenancyFilterSet
  11. from utilities.filters import (
  12. ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter,
  13. )
  14. from virtualization.models import VirtualMachine, VMInterface
  15. from .choices import *
  16. from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
  17. __all__ = (
  18. 'AggregateFilterSet',
  19. 'IPAddressFilterSet',
  20. 'PrefixFilterSet',
  21. 'RIRFilterSet',
  22. 'RoleFilterSet',
  23. 'RouteTargetFilterSet',
  24. 'ServiceFilterSet',
  25. 'VLANFilterSet',
  26. 'VLANGroupFilterSet',
  27. 'VRFFilterSet',
  28. )
  29. class VRFFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  30. q = django_filters.CharFilter(
  31. method='search',
  32. label='Search',
  33. )
  34. import_target_id = django_filters.ModelMultipleChoiceFilter(
  35. field_name='import_targets',
  36. queryset=RouteTarget.objects.all(),
  37. label='Import target',
  38. )
  39. import_target = django_filters.ModelMultipleChoiceFilter(
  40. field_name='import_targets__name',
  41. queryset=RouteTarget.objects.all(),
  42. to_field_name='name',
  43. label='Import target (name)',
  44. )
  45. export_target_id = django_filters.ModelMultipleChoiceFilter(
  46. field_name='export_targets',
  47. queryset=RouteTarget.objects.all(),
  48. label='Export target',
  49. )
  50. export_target = django_filters.ModelMultipleChoiceFilter(
  51. field_name='export_targets__name',
  52. queryset=RouteTarget.objects.all(),
  53. to_field_name='name',
  54. label='Export target (name)',
  55. )
  56. tag = TagFilter()
  57. def search(self, queryset, name, value):
  58. if not value.strip():
  59. return queryset
  60. return queryset.filter(
  61. Q(name__icontains=value) |
  62. Q(rd__icontains=value) |
  63. Q(description__icontains=value)
  64. )
  65. class Meta:
  66. model = VRF
  67. fields = ['id', 'name', 'rd', 'enforce_unique']
  68. class RouteTargetFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  69. q = django_filters.CharFilter(
  70. method='search',
  71. label='Search',
  72. )
  73. importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
  74. field_name='importing_vrfs',
  75. queryset=VRF.objects.all(),
  76. label='Importing VRF',
  77. )
  78. importing_vrf = django_filters.ModelMultipleChoiceFilter(
  79. field_name='importing_vrfs__rd',
  80. queryset=VRF.objects.all(),
  81. to_field_name='rd',
  82. label='Import VRF (RD)',
  83. )
  84. exporting_vrf_id = django_filters.ModelMultipleChoiceFilter(
  85. field_name='exporting_vrfs',
  86. queryset=VRF.objects.all(),
  87. label='Exporting VRF',
  88. )
  89. exporting_vrf = django_filters.ModelMultipleChoiceFilter(
  90. field_name='exporting_vrfs__rd',
  91. queryset=VRF.objects.all(),
  92. to_field_name='rd',
  93. label='Export VRF (RD)',
  94. )
  95. tag = TagFilter()
  96. def search(self, queryset, name, value):
  97. if not value.strip():
  98. return queryset
  99. return queryset.filter(
  100. Q(name__icontains=value) |
  101. Q(description__icontains=value)
  102. )
  103. class Meta:
  104. model = RouteTarget
  105. fields = ['id', 'name']
  106. class RIRFilterSet(OrganizationalModelFilterSet):
  107. class Meta:
  108. model = RIR
  109. fields = ['id', 'name', 'slug', 'is_private', 'description']
  110. class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  111. q = django_filters.CharFilter(
  112. method='search',
  113. label='Search',
  114. )
  115. family = django_filters.NumberFilter(
  116. field_name='prefix',
  117. lookup_expr='family'
  118. )
  119. prefix = django_filters.CharFilter(
  120. method='filter_prefix',
  121. label='Prefix',
  122. )
  123. rir_id = django_filters.ModelMultipleChoiceFilter(
  124. queryset=RIR.objects.all(),
  125. label='RIR (ID)',
  126. )
  127. rir = django_filters.ModelMultipleChoiceFilter(
  128. field_name='rir__slug',
  129. queryset=RIR.objects.all(),
  130. to_field_name='slug',
  131. label='RIR (slug)',
  132. )
  133. tag = TagFilter()
  134. class Meta:
  135. model = Aggregate
  136. fields = ['id', 'date_added']
  137. def search(self, queryset, name, value):
  138. if not value.strip():
  139. return queryset
  140. qs_filter = Q(description__icontains=value)
  141. try:
  142. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  143. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  144. except (AddrFormatError, ValueError):
  145. pass
  146. return queryset.filter(qs_filter)
  147. def filter_prefix(self, queryset, name, value):
  148. if not value.strip():
  149. return queryset
  150. try:
  151. query = str(netaddr.IPNetwork(value).cidr)
  152. return queryset.filter(prefix=query)
  153. except (AddrFormatError, ValueError):
  154. return queryset.none()
  155. class RoleFilterSet(OrganizationalModelFilterSet):
  156. q = django_filters.CharFilter(
  157. method='search',
  158. label='Search',
  159. )
  160. class Meta:
  161. model = Role
  162. fields = ['id', 'name', 'slug']
  163. class PrefixFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  164. q = django_filters.CharFilter(
  165. method='search',
  166. label='Search',
  167. )
  168. family = django_filters.NumberFilter(
  169. field_name='prefix',
  170. lookup_expr='family'
  171. )
  172. prefix = MultiValueCharFilter(
  173. method='filter_prefix',
  174. label='Prefix',
  175. )
  176. within = django_filters.CharFilter(
  177. method='search_within',
  178. label='Within prefix',
  179. )
  180. within_include = django_filters.CharFilter(
  181. method='search_within_include',
  182. label='Within and including prefix',
  183. )
  184. contains = django_filters.CharFilter(
  185. method='search_contains',
  186. label='Prefixes which contain this prefix or IP',
  187. )
  188. mask_length = django_filters.NumberFilter(
  189. field_name='prefix',
  190. lookup_expr='net_mask_length'
  191. )
  192. mask_length__gte = django_filters.NumberFilter(
  193. field_name='prefix',
  194. lookup_expr='net_mask_length__gte'
  195. )
  196. mask_length__lte = django_filters.NumberFilter(
  197. field_name='prefix',
  198. lookup_expr='net_mask_length__lte'
  199. )
  200. vrf_id = django_filters.ModelMultipleChoiceFilter(
  201. queryset=VRF.objects.all(),
  202. label='VRF',
  203. )
  204. vrf = django_filters.ModelMultipleChoiceFilter(
  205. field_name='vrf__rd',
  206. queryset=VRF.objects.all(),
  207. to_field_name='rd',
  208. label='VRF (RD)',
  209. )
  210. present_in_vrf_id = django_filters.ModelChoiceFilter(
  211. queryset=VRF.objects.all(),
  212. method='filter_present_in_vrf',
  213. label='VRF'
  214. )
  215. present_in_vrf = django_filters.ModelChoiceFilter(
  216. queryset=VRF.objects.all(),
  217. method='filter_present_in_vrf',
  218. to_field_name='rd',
  219. label='VRF (RD)',
  220. )
  221. region_id = TreeNodeMultipleChoiceFilter(
  222. queryset=Region.objects.all(),
  223. field_name='site__region',
  224. lookup_expr='in',
  225. label='Region (ID)',
  226. )
  227. region = TreeNodeMultipleChoiceFilter(
  228. queryset=Region.objects.all(),
  229. field_name='site__region',
  230. lookup_expr='in',
  231. to_field_name='slug',
  232. label='Region (slug)',
  233. )
  234. site_group_id = TreeNodeMultipleChoiceFilter(
  235. queryset=SiteGroup.objects.all(),
  236. field_name='site__group',
  237. lookup_expr='in',
  238. label='Site group (ID)',
  239. )
  240. site_group = TreeNodeMultipleChoiceFilter(
  241. queryset=SiteGroup.objects.all(),
  242. field_name='site__group',
  243. lookup_expr='in',
  244. to_field_name='slug',
  245. label='Site group (slug)',
  246. )
  247. site_id = django_filters.ModelMultipleChoiceFilter(
  248. queryset=Site.objects.all(),
  249. label='Site (ID)',
  250. )
  251. site = django_filters.ModelMultipleChoiceFilter(
  252. field_name='site__slug',
  253. queryset=Site.objects.all(),
  254. to_field_name='slug',
  255. label='Site (slug)',
  256. )
  257. vlan_id = django_filters.ModelMultipleChoiceFilter(
  258. queryset=VLAN.objects.all(),
  259. label='VLAN (ID)',
  260. )
  261. vlan_vid = django_filters.NumberFilter(
  262. field_name='vlan__vid',
  263. label='VLAN number (1-4095)',
  264. )
  265. role_id = django_filters.ModelMultipleChoiceFilter(
  266. queryset=Role.objects.all(),
  267. label='Role (ID)',
  268. )
  269. role = django_filters.ModelMultipleChoiceFilter(
  270. field_name='role__slug',
  271. queryset=Role.objects.all(),
  272. to_field_name='slug',
  273. label='Role (slug)',
  274. )
  275. status = django_filters.MultipleChoiceFilter(
  276. choices=PrefixStatusChoices,
  277. null_value=None
  278. )
  279. tag = TagFilter()
  280. class Meta:
  281. model = Prefix
  282. fields = ['id', 'is_pool', 'mark_utilized']
  283. def search(self, queryset, name, value):
  284. if not value.strip():
  285. return queryset
  286. qs_filter = Q(description__icontains=value)
  287. try:
  288. prefix = str(netaddr.IPNetwork(value.strip()).cidr)
  289. qs_filter |= Q(prefix__net_contains_or_equals=prefix)
  290. except (AddrFormatError, ValueError):
  291. pass
  292. return queryset.filter(qs_filter)
  293. def filter_prefix(self, queryset, name, value):
  294. query_values = []
  295. for v in value:
  296. try:
  297. query_values.append(netaddr.IPNetwork(v))
  298. except (AddrFormatError, ValueError):
  299. pass
  300. return queryset.filter(prefix__in=query_values)
  301. def search_within(self, queryset, name, value):
  302. value = value.strip()
  303. if not value:
  304. return queryset
  305. try:
  306. query = str(netaddr.IPNetwork(value).cidr)
  307. return queryset.filter(prefix__net_contained=query)
  308. except (AddrFormatError, ValueError):
  309. return queryset.none()
  310. def search_within_include(self, queryset, name, value):
  311. value = value.strip()
  312. if not value:
  313. return queryset
  314. try:
  315. query = str(netaddr.IPNetwork(value).cidr)
  316. return queryset.filter(prefix__net_contained_or_equal=query)
  317. except (AddrFormatError, ValueError):
  318. return queryset.none()
  319. def search_contains(self, queryset, name, value):
  320. value = value.strip()
  321. if not value:
  322. return queryset
  323. try:
  324. # Searching by prefix
  325. if '/' in value:
  326. return queryset.filter(prefix__net_contains_or_equals=str(netaddr.IPNetwork(value).cidr))
  327. # Searching by IP address
  328. else:
  329. return queryset.filter(prefix__net_contains=str(netaddr.IPAddress(value)))
  330. except (AddrFormatError, ValueError):
  331. return queryset.none()
  332. def filter_present_in_vrf(self, queryset, name, vrf):
  333. if vrf is None:
  334. return queryset.none
  335. return queryset.filter(
  336. Q(vrf=vrf) |
  337. Q(vrf__export_targets__in=vrf.import_targets.all())
  338. )
  339. class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  340. q = django_filters.CharFilter(
  341. method='search',
  342. label='Search',
  343. )
  344. family = django_filters.NumberFilter(
  345. field_name='address',
  346. lookup_expr='family'
  347. )
  348. parent = django_filters.CharFilter(
  349. method='search_by_parent',
  350. label='Parent prefix',
  351. )
  352. address = MultiValueCharFilter(
  353. method='filter_address',
  354. label='Address',
  355. )
  356. mask_length = django_filters.NumberFilter(
  357. method='filter_mask_length',
  358. label='Mask length',
  359. )
  360. vrf_id = django_filters.ModelMultipleChoiceFilter(
  361. queryset=VRF.objects.all(),
  362. label='VRF',
  363. )
  364. vrf = django_filters.ModelMultipleChoiceFilter(
  365. field_name='vrf__rd',
  366. queryset=VRF.objects.all(),
  367. to_field_name='rd',
  368. label='VRF (RD)',
  369. )
  370. present_in_vrf_id = django_filters.ModelChoiceFilter(
  371. queryset=VRF.objects.all(),
  372. method='filter_present_in_vrf',
  373. label='VRF'
  374. )
  375. present_in_vrf = django_filters.ModelChoiceFilter(
  376. queryset=VRF.objects.all(),
  377. method='filter_present_in_vrf',
  378. to_field_name='rd',
  379. label='VRF (RD)',
  380. )
  381. device = MultiValueCharFilter(
  382. method='filter_device',
  383. field_name='name',
  384. label='Device (name)',
  385. )
  386. device_id = MultiValueNumberFilter(
  387. method='filter_device',
  388. field_name='pk',
  389. label='Device (ID)',
  390. )
  391. virtual_machine = MultiValueCharFilter(
  392. method='filter_virtual_machine',
  393. field_name='name',
  394. label='Virtual machine (name)',
  395. )
  396. virtual_machine_id = MultiValueNumberFilter(
  397. method='filter_virtual_machine',
  398. field_name='pk',
  399. label='Virtual machine (ID)',
  400. )
  401. interface = django_filters.ModelMultipleChoiceFilter(
  402. field_name='interface__name',
  403. queryset=Interface.objects.all(),
  404. to_field_name='name',
  405. label='Interface (name)',
  406. )
  407. interface_id = django_filters.ModelMultipleChoiceFilter(
  408. field_name='interface',
  409. queryset=Interface.objects.all(),
  410. label='Interface (ID)',
  411. )
  412. vminterface = django_filters.ModelMultipleChoiceFilter(
  413. field_name='vminterface__name',
  414. queryset=VMInterface.objects.all(),
  415. to_field_name='name',
  416. label='VM interface (name)',
  417. )
  418. vminterface_id = django_filters.ModelMultipleChoiceFilter(
  419. field_name='vminterface',
  420. queryset=VMInterface.objects.all(),
  421. label='VM interface (ID)',
  422. )
  423. assigned_to_interface = django_filters.BooleanFilter(
  424. method='_assigned_to_interface',
  425. label='Is assigned to an interface',
  426. )
  427. status = django_filters.MultipleChoiceFilter(
  428. choices=IPAddressStatusChoices,
  429. null_value=None
  430. )
  431. role = django_filters.MultipleChoiceFilter(
  432. choices=IPAddressRoleChoices
  433. )
  434. tag = TagFilter()
  435. class Meta:
  436. model = IPAddress
  437. fields = ['id', 'dns_name', 'description']
  438. def search(self, queryset, name, value):
  439. if not value.strip():
  440. return queryset
  441. qs_filter = (
  442. Q(dns_name__icontains=value) |
  443. Q(description__icontains=value) |
  444. Q(address__istartswith=value)
  445. )
  446. return queryset.filter(qs_filter)
  447. def search_by_parent(self, queryset, name, value):
  448. value = value.strip()
  449. if not value:
  450. return queryset
  451. try:
  452. query = str(netaddr.IPNetwork(value.strip()).cidr)
  453. return queryset.filter(address__net_host_contained=query)
  454. except (AddrFormatError, ValueError):
  455. return queryset.none()
  456. def filter_address(self, queryset, name, value):
  457. try:
  458. return queryset.filter(address__net_in=value)
  459. except ValidationError:
  460. return queryset.none()
  461. def filter_mask_length(self, queryset, name, value):
  462. if not value:
  463. return queryset
  464. return queryset.filter(address__net_mask_length=value)
  465. def filter_present_in_vrf(self, queryset, name, vrf):
  466. if vrf is None:
  467. return queryset.none
  468. return queryset.filter(
  469. Q(vrf=vrf) |
  470. Q(vrf__export_targets__in=vrf.import_targets.all())
  471. )
  472. def filter_device(self, queryset, name, value):
  473. devices = Device.objects.filter(**{'{}__in'.format(name): value})
  474. if not devices.exists():
  475. return queryset.none()
  476. interface_ids = []
  477. for device in devices:
  478. interface_ids.extend(device.vc_interfaces().values_list('id', flat=True))
  479. return queryset.filter(
  480. interface__in=interface_ids
  481. )
  482. def filter_virtual_machine(self, queryset, name, value):
  483. virtual_machines = VirtualMachine.objects.filter(**{'{}__in'.format(name): value})
  484. if not virtual_machines.exists():
  485. return queryset.none()
  486. interface_ids = []
  487. for vm in virtual_machines:
  488. interface_ids.extend(vm.interfaces.values_list('id', flat=True))
  489. return queryset.filter(
  490. vminterface__in=interface_ids
  491. )
  492. def _assigned_to_interface(self, queryset, name, value):
  493. return queryset.exclude(assigned_object_id__isnull=value)
  494. class VLANGroupFilterSet(OrganizationalModelFilterSet):
  495. q = django_filters.CharFilter(
  496. method='search',
  497. label='Search',
  498. )
  499. scope_type = ContentTypeFilter()
  500. region = django_filters.NumberFilter(
  501. method='filter_scope'
  502. )
  503. sitegroup = django_filters.NumberFilter(
  504. method='filter_scope'
  505. )
  506. site = django_filters.NumberFilter(
  507. method='filter_scope'
  508. )
  509. location = django_filters.NumberFilter(
  510. method='filter_scope'
  511. )
  512. rack = django_filters.NumberFilter(
  513. method='filter_scope'
  514. )
  515. clustergroup = django_filters.NumberFilter(
  516. method='filter_scope'
  517. )
  518. cluster = django_filters.NumberFilter(
  519. method='filter_scope'
  520. )
  521. class Meta:
  522. model = VLANGroup
  523. fields = ['id', 'name', 'slug', 'description', 'scope_id']
  524. def search(self, queryset, name, value):
  525. if not value.strip():
  526. return queryset
  527. qs_filter = (
  528. Q(name__icontains=value) |
  529. Q(description__icontains=value)
  530. )
  531. return queryset.filter(qs_filter)
  532. def filter_scope(self, queryset, name, value):
  533. return queryset.filter(
  534. scope_type=ContentType.objects.get(model=name),
  535. scope_id=value
  536. )
  537. class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
  538. q = django_filters.CharFilter(
  539. method='search',
  540. label='Search',
  541. )
  542. region_id = TreeNodeMultipleChoiceFilter(
  543. queryset=Region.objects.all(),
  544. field_name='site__region',
  545. lookup_expr='in',
  546. label='Region (ID)',
  547. )
  548. region = TreeNodeMultipleChoiceFilter(
  549. queryset=Region.objects.all(),
  550. field_name='site__region',
  551. lookup_expr='in',
  552. to_field_name='slug',
  553. label='Region (slug)',
  554. )
  555. site_group_id = TreeNodeMultipleChoiceFilter(
  556. queryset=SiteGroup.objects.all(),
  557. field_name='site__group',
  558. lookup_expr='in',
  559. label='Site group (ID)',
  560. )
  561. site_group = TreeNodeMultipleChoiceFilter(
  562. queryset=SiteGroup.objects.all(),
  563. field_name='site__group',
  564. lookup_expr='in',
  565. to_field_name='slug',
  566. label='Site group (slug)',
  567. )
  568. site_id = django_filters.ModelMultipleChoiceFilter(
  569. queryset=Site.objects.all(),
  570. label='Site (ID)',
  571. )
  572. site = django_filters.ModelMultipleChoiceFilter(
  573. field_name='site__slug',
  574. queryset=Site.objects.all(),
  575. to_field_name='slug',
  576. label='Site (slug)',
  577. )
  578. group_id = django_filters.ModelMultipleChoiceFilter(
  579. queryset=VLANGroup.objects.all(),
  580. label='Group (ID)',
  581. )
  582. group = django_filters.ModelMultipleChoiceFilter(
  583. field_name='group__slug',
  584. queryset=VLANGroup.objects.all(),
  585. to_field_name='slug',
  586. label='Group',
  587. )
  588. role_id = django_filters.ModelMultipleChoiceFilter(
  589. queryset=Role.objects.all(),
  590. label='Role (ID)',
  591. )
  592. role = django_filters.ModelMultipleChoiceFilter(
  593. field_name='role__slug',
  594. queryset=Role.objects.all(),
  595. to_field_name='slug',
  596. label='Role (slug)',
  597. )
  598. status = django_filters.MultipleChoiceFilter(
  599. choices=VLANStatusChoices,
  600. null_value=None
  601. )
  602. available_on_device = django_filters.ModelChoiceFilter(
  603. queryset=Device.objects.all(),
  604. method='get_for_device'
  605. )
  606. available_on_virtualmachine = django_filters.ModelChoiceFilter(
  607. queryset=VirtualMachine.objects.all(),
  608. method='get_for_virtualmachine'
  609. )
  610. tag = TagFilter()
  611. class Meta:
  612. model = VLAN
  613. fields = ['id', 'vid', 'name']
  614. def search(self, queryset, name, value):
  615. if not value.strip():
  616. return queryset
  617. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  618. try:
  619. qs_filter |= Q(vid=int(value.strip()))
  620. except ValueError:
  621. pass
  622. return queryset.filter(qs_filter)
  623. def get_for_device(self, queryset, name, value):
  624. return queryset.get_for_device(value)
  625. def get_for_virtualmachine(self, queryset, name, value):
  626. return queryset.get_for_virtualmachine(value)
  627. class ServiceFilterSet(PrimaryModelFilterSet):
  628. q = django_filters.CharFilter(
  629. method='search',
  630. label='Search',
  631. )
  632. device_id = django_filters.ModelMultipleChoiceFilter(
  633. queryset=Device.objects.all(),
  634. label='Device (ID)',
  635. )
  636. device = django_filters.ModelMultipleChoiceFilter(
  637. field_name='device__name',
  638. queryset=Device.objects.all(),
  639. to_field_name='name',
  640. label='Device (name)',
  641. )
  642. virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
  643. queryset=VirtualMachine.objects.all(),
  644. label='Virtual machine (ID)',
  645. )
  646. virtual_machine = django_filters.ModelMultipleChoiceFilter(
  647. field_name='virtual_machine__name',
  648. queryset=VirtualMachine.objects.all(),
  649. to_field_name='name',
  650. label='Virtual machine (name)',
  651. )
  652. port = NumericArrayFilter(
  653. field_name='ports',
  654. lookup_expr='contains'
  655. )
  656. tag = TagFilter()
  657. class Meta:
  658. model = Service
  659. fields = ['id', 'name', 'protocol']
  660. def search(self, queryset, name, value):
  661. if not value.strip():
  662. return queryset
  663. qs_filter = Q(name__icontains=value) | Q(description__icontains=value)
  664. return queryset.filter(qs_filter)