2
0

filtersets.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. import django_filters
  2. from django.contrib.auth import get_user_model
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.db.models import Q
  5. from django.utils.translation import gettext as _
  6. from core.models import DataSource, ObjectType
  7. from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
  8. from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet
  9. from tenancy.models import Tenant, TenantGroup
  10. from utilities.filters import ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
  11. from virtualization.models import Cluster, ClusterGroup, ClusterType
  12. from .choices import *
  13. from .filters import TagFilter
  14. from .models import *
  15. __all__ = (
  16. 'BookmarkFilterSet',
  17. 'ConfigContextFilterSet',
  18. 'ConfigTemplateFilterSet',
  19. 'CustomFieldChoiceSetFilterSet',
  20. 'CustomFieldFilterSet',
  21. 'CustomLinkFilterSet',
  22. 'EventRuleFilterSet',
  23. 'ExportTemplateFilterSet',
  24. 'ImageAttachmentFilterSet',
  25. 'JournalEntryFilterSet',
  26. 'LocalConfigContextFilterSet',
  27. 'ObjectChangeFilterSet',
  28. 'ObjectTypeFilterSet',
  29. 'SavedFilterFilterSet',
  30. 'ScriptFilterSet',
  31. 'TagFilterSet',
  32. 'WebhookFilterSet',
  33. )
  34. class ScriptFilterSet(BaseFilterSet):
  35. q = django_filters.CharFilter(
  36. method='search',
  37. label=_('Search'),
  38. )
  39. class Meta:
  40. model = Script
  41. fields = [
  42. 'id', 'name',
  43. ]
  44. def search(self, queryset, name, value):
  45. if not value.strip():
  46. return queryset
  47. return queryset.filter(
  48. Q(name__icontains=value)
  49. )
  50. class WebhookFilterSet(NetBoxModelFilterSet):
  51. q = django_filters.CharFilter(
  52. method='search',
  53. label=_('Search'),
  54. )
  55. http_method = django_filters.MultipleChoiceFilter(
  56. choices=WebhookHttpMethodChoices
  57. )
  58. payload_url = MultiValueCharFilter(
  59. lookup_expr='icontains'
  60. )
  61. class Meta:
  62. model = Webhook
  63. fields = [
  64. 'id', 'name', 'payload_url', 'http_method', 'http_content_type', 'secret', 'ssl_verification',
  65. 'ca_file_path', 'description',
  66. ]
  67. def search(self, queryset, name, value):
  68. if not value.strip():
  69. return queryset
  70. return queryset.filter(
  71. Q(name__icontains=value) |
  72. Q(description__icontains=value) |
  73. Q(payload_url__icontains=value)
  74. )
  75. class EventRuleFilterSet(NetBoxModelFilterSet):
  76. q = django_filters.CharFilter(
  77. method='search',
  78. label=_('Search'),
  79. )
  80. object_type_id = MultiValueNumberFilter(
  81. field_name='object_types__id'
  82. )
  83. object_type = ContentTypeFilter(
  84. field_name='object_types'
  85. )
  86. action_type = django_filters.MultipleChoiceFilter(
  87. choices=EventRuleActionChoices
  88. )
  89. action_object_type = ContentTypeFilter()
  90. action_object_id = MultiValueNumberFilter()
  91. class Meta:
  92. model = EventRule
  93. fields = [
  94. 'id', 'name', 'type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end', 'enabled',
  95. 'action_type', 'description',
  96. ]
  97. def search(self, queryset, name, value):
  98. if not value.strip():
  99. return queryset
  100. return queryset.filter(
  101. Q(name__icontains=value) |
  102. Q(description__icontains=value) |
  103. Q(comments__icontains=value)
  104. )
  105. class CustomFieldFilterSet(BaseFilterSet):
  106. q = django_filters.CharFilter(
  107. method='search',
  108. label=_('Search'),
  109. )
  110. type = django_filters.MultipleChoiceFilter(
  111. choices=CustomFieldTypeChoices
  112. )
  113. object_type_id = MultiValueNumberFilter(
  114. field_name='object_types__id'
  115. )
  116. object_type = ContentTypeFilter(
  117. field_name='object_types'
  118. )
  119. choice_set_id = django_filters.ModelMultipleChoiceFilter(
  120. queryset=CustomFieldChoiceSet.objects.all()
  121. )
  122. choice_set = django_filters.ModelMultipleChoiceFilter(
  123. field_name='choice_set__name',
  124. queryset=CustomFieldChoiceSet.objects.all(),
  125. to_field_name='name'
  126. )
  127. class Meta:
  128. model = CustomField
  129. fields = [
  130. 'id', 'name', 'group_name', 'required', 'search_weight', 'filter_logic', 'ui_visible', 'ui_editable',
  131. 'weight', 'is_cloneable', 'description',
  132. ]
  133. def search(self, queryset, name, value):
  134. if not value.strip():
  135. return queryset
  136. return queryset.filter(
  137. Q(name__icontains=value) |
  138. Q(label__icontains=value) |
  139. Q(group_name__icontains=value) |
  140. Q(description__icontains=value)
  141. )
  142. class CustomFieldChoiceSetFilterSet(BaseFilterSet):
  143. q = django_filters.CharFilter(
  144. method='search',
  145. label=_('Search'),
  146. )
  147. choice = MultiValueCharFilter(
  148. method='filter_by_choice'
  149. )
  150. class Meta:
  151. model = CustomFieldChoiceSet
  152. fields = [
  153. 'id', 'name', 'description', 'base_choices', 'order_alphabetically',
  154. ]
  155. def search(self, queryset, name, value):
  156. if not value.strip():
  157. return queryset
  158. return queryset.filter(
  159. Q(name__icontains=value) |
  160. Q(description__icontains=value)
  161. )
  162. def filter_by_choice(self, queryset, name, value):
  163. # TODO: Support case-insensitive matching
  164. return queryset.filter(extra_choices__overlap=value)
  165. class CustomLinkFilterSet(BaseFilterSet):
  166. q = django_filters.CharFilter(
  167. method='search',
  168. label=_('Search'),
  169. )
  170. object_type_id = MultiValueNumberFilter(
  171. field_name='object_types__id'
  172. )
  173. object_type = ContentTypeFilter(
  174. field_name='object_types'
  175. )
  176. class Meta:
  177. model = CustomLink
  178. fields = [
  179. 'id', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name', 'new_window',
  180. ]
  181. def search(self, queryset, name, value):
  182. if not value.strip():
  183. return queryset
  184. return queryset.filter(
  185. Q(name__icontains=value) |
  186. Q(link_text__icontains=value) |
  187. Q(link_url__icontains=value) |
  188. Q(group_name__icontains=value)
  189. )
  190. class ExportTemplateFilterSet(BaseFilterSet):
  191. q = django_filters.CharFilter(
  192. method='search',
  193. label=_('Search'),
  194. )
  195. object_type_id = MultiValueNumberFilter(
  196. field_name='object_types__id'
  197. )
  198. object_type = ContentTypeFilter(
  199. field_name='object_types'
  200. )
  201. data_source_id = django_filters.ModelMultipleChoiceFilter(
  202. queryset=DataSource.objects.all(),
  203. label=_('Data source (ID)'),
  204. )
  205. data_file_id = django_filters.ModelMultipleChoiceFilter(
  206. queryset=DataSource.objects.all(),
  207. label=_('Data file (ID)'),
  208. )
  209. class Meta:
  210. model = ExportTemplate
  211. fields = ['id', 'name', 'description', 'data_synced']
  212. def search(self, queryset, name, value):
  213. if not value.strip():
  214. return queryset
  215. return queryset.filter(
  216. Q(name__icontains=value) |
  217. Q(description__icontains=value)
  218. )
  219. class SavedFilterFilterSet(BaseFilterSet):
  220. q = django_filters.CharFilter(
  221. method='search',
  222. label=_('Search'),
  223. )
  224. object_type_id = MultiValueNumberFilter(
  225. field_name='object_types__id'
  226. )
  227. object_type = ContentTypeFilter(
  228. field_name='object_types'
  229. )
  230. user_id = django_filters.ModelMultipleChoiceFilter(
  231. queryset=get_user_model().objects.all(),
  232. label=_('User (ID)'),
  233. )
  234. user = django_filters.ModelMultipleChoiceFilter(
  235. field_name='user__username',
  236. queryset=get_user_model().objects.all(),
  237. to_field_name='username',
  238. label=_('User (name)'),
  239. )
  240. usable = django_filters.BooleanFilter(
  241. method='_usable'
  242. )
  243. class Meta:
  244. model = SavedFilter
  245. fields = ['id', 'name', 'slug', 'description', 'enabled', 'shared', 'weight']
  246. def search(self, queryset, name, value):
  247. if not value.strip():
  248. return queryset
  249. return queryset.filter(
  250. Q(name__icontains=value) |
  251. Q(description__icontains=value)
  252. )
  253. def _usable(self, queryset, name, value):
  254. """
  255. Return only SavedFilters that are both enabled and are shared (or belong to the current user).
  256. """
  257. user = self.request.user if self.request else None
  258. if not user or user.is_anonymous:
  259. if value:
  260. return queryset.filter(enabled=True, shared=True)
  261. return queryset.filter(Q(enabled=False) | Q(shared=False))
  262. if value:
  263. return queryset.filter(enabled=True).filter(Q(shared=True) | Q(user=user))
  264. return queryset.filter(Q(enabled=False) | Q(Q(shared=False) & ~Q(user=user)))
  265. class BookmarkFilterSet(BaseFilterSet):
  266. created = django_filters.DateTimeFilter()
  267. object_type_id = MultiValueNumberFilter()
  268. object_type = ContentTypeFilter()
  269. user_id = django_filters.ModelMultipleChoiceFilter(
  270. queryset=get_user_model().objects.all(),
  271. label=_('User (ID)'),
  272. )
  273. user = django_filters.ModelMultipleChoiceFilter(
  274. field_name='user__username',
  275. queryset=get_user_model().objects.all(),
  276. to_field_name='username',
  277. label=_('User (name)'),
  278. )
  279. class Meta:
  280. model = Bookmark
  281. fields = ['id', 'object_id']
  282. class ImageAttachmentFilterSet(BaseFilterSet):
  283. q = django_filters.CharFilter(
  284. method='search',
  285. label=_('Search'),
  286. )
  287. created = django_filters.DateTimeFilter()
  288. object_type = ContentTypeFilter()
  289. class Meta:
  290. model = ImageAttachment
  291. fields = ['id', 'object_type_id', 'object_id', 'name']
  292. def search(self, queryset, name, value):
  293. if not value.strip():
  294. return queryset
  295. return queryset.filter(name__icontains=value)
  296. class JournalEntryFilterSet(NetBoxModelFilterSet):
  297. created = django_filters.DateTimeFromToRangeFilter()
  298. assigned_object_type = ContentTypeFilter()
  299. assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
  300. queryset=ContentType.objects.all()
  301. )
  302. created_by_id = django_filters.ModelMultipleChoiceFilter(
  303. queryset=get_user_model().objects.all(),
  304. label=_('User (ID)'),
  305. )
  306. created_by = django_filters.ModelMultipleChoiceFilter(
  307. field_name='created_by__username',
  308. queryset=get_user_model().objects.all(),
  309. to_field_name='username',
  310. label=_('User (name)'),
  311. )
  312. kind = django_filters.MultipleChoiceFilter(
  313. choices=JournalEntryKindChoices
  314. )
  315. class Meta:
  316. model = JournalEntry
  317. fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind']
  318. def search(self, queryset, name, value):
  319. if not value.strip():
  320. return queryset
  321. return queryset.filter(comments__icontains=value)
  322. class TagFilterSet(ChangeLoggedModelFilterSet):
  323. q = django_filters.CharFilter(
  324. method='search',
  325. label=_('Search'),
  326. )
  327. content_type = MultiValueCharFilter(
  328. method='_content_type'
  329. )
  330. content_type_id = MultiValueNumberFilter(
  331. method='_content_type_id'
  332. )
  333. for_object_type_id = MultiValueNumberFilter(
  334. method='_for_object_type'
  335. )
  336. class Meta:
  337. model = Tag
  338. fields = ['id', 'name', 'slug', 'color', 'description', 'object_types']
  339. def search(self, queryset, name, value):
  340. if not value.strip():
  341. return queryset
  342. return queryset.filter(
  343. Q(name__icontains=value) |
  344. Q(slug__icontains=value) |
  345. Q(description__icontains=value)
  346. )
  347. def _content_type(self, queryset, name, values):
  348. ct_filter = Q()
  349. # Compile list of app_label & model pairings
  350. for value in values:
  351. try:
  352. app_label, model = value.lower().split('.')
  353. ct_filter |= Q(
  354. app_label=app_label,
  355. model=model
  356. )
  357. except ValueError:
  358. pass
  359. # Get ContentType instances
  360. content_types = ContentType.objects.filter(ct_filter)
  361. return queryset.filter(extras_taggeditem_items__content_type__in=content_types).distinct()
  362. def _content_type_id(self, queryset, name, values):
  363. # Get ContentType instances
  364. content_types = ContentType.objects.filter(pk__in=values)
  365. return queryset.filter(extras_taggeditem_items__content_type__in=content_types).distinct()
  366. def _for_object_type(self, queryset, name, values):
  367. return queryset.filter(
  368. Q(object_types__id__in=values) | Q(object_types__isnull=True)
  369. )
  370. class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
  371. q = django_filters.CharFilter(
  372. method='search',
  373. label=_('Search'),
  374. )
  375. region_id = django_filters.ModelMultipleChoiceFilter(
  376. field_name='regions',
  377. queryset=Region.objects.all(),
  378. label=_('Region'),
  379. )
  380. region = django_filters.ModelMultipleChoiceFilter(
  381. field_name='regions__slug',
  382. queryset=Region.objects.all(),
  383. to_field_name='slug',
  384. label=_('Region (slug)'),
  385. )
  386. site_group = django_filters.ModelMultipleChoiceFilter(
  387. field_name='site_groups__slug',
  388. queryset=SiteGroup.objects.all(),
  389. to_field_name='slug',
  390. label=_('Site group (slug)'),
  391. )
  392. site_group_id = django_filters.ModelMultipleChoiceFilter(
  393. field_name='site_groups',
  394. queryset=SiteGroup.objects.all(),
  395. label=_('Site group'),
  396. )
  397. site_id = django_filters.ModelMultipleChoiceFilter(
  398. field_name='sites',
  399. queryset=Site.objects.all(),
  400. label=_('Site'),
  401. )
  402. site = django_filters.ModelMultipleChoiceFilter(
  403. field_name='sites__slug',
  404. queryset=Site.objects.all(),
  405. to_field_name='slug',
  406. label=_('Site (slug)'),
  407. )
  408. location_id = django_filters.ModelMultipleChoiceFilter(
  409. field_name='locations',
  410. queryset=Location.objects.all(),
  411. label=_('Location'),
  412. )
  413. location = django_filters.ModelMultipleChoiceFilter(
  414. field_name='locations__slug',
  415. queryset=Location.objects.all(),
  416. to_field_name='slug',
  417. label=_('Location (slug)'),
  418. )
  419. device_type_id = django_filters.ModelMultipleChoiceFilter(
  420. field_name='device_types',
  421. queryset=DeviceType.objects.all(),
  422. label=_('Device type'),
  423. )
  424. role_id = django_filters.ModelMultipleChoiceFilter(
  425. field_name='roles',
  426. queryset=DeviceRole.objects.all(),
  427. label=_('Role'),
  428. )
  429. role = django_filters.ModelMultipleChoiceFilter(
  430. field_name='roles__slug',
  431. queryset=DeviceRole.objects.all(),
  432. to_field_name='slug',
  433. label=_('Role (slug)'),
  434. )
  435. platform_id = django_filters.ModelMultipleChoiceFilter(
  436. field_name='platforms',
  437. queryset=Platform.objects.all(),
  438. label=_('Platform'),
  439. )
  440. platform = django_filters.ModelMultipleChoiceFilter(
  441. field_name='platforms__slug',
  442. queryset=Platform.objects.all(),
  443. to_field_name='slug',
  444. label=_('Platform (slug)'),
  445. )
  446. cluster_type_id = django_filters.ModelMultipleChoiceFilter(
  447. field_name='cluster_types',
  448. queryset=ClusterType.objects.all(),
  449. label=_('Cluster type'),
  450. )
  451. cluster_type = django_filters.ModelMultipleChoiceFilter(
  452. field_name='cluster_types__slug',
  453. queryset=ClusterType.objects.all(),
  454. to_field_name='slug',
  455. label=_('Cluster type (slug)'),
  456. )
  457. cluster_group_id = django_filters.ModelMultipleChoiceFilter(
  458. field_name='cluster_groups',
  459. queryset=ClusterGroup.objects.all(),
  460. label=_('Cluster group'),
  461. )
  462. cluster_group = django_filters.ModelMultipleChoiceFilter(
  463. field_name='cluster_groups__slug',
  464. queryset=ClusterGroup.objects.all(),
  465. to_field_name='slug',
  466. label=_('Cluster group (slug)'),
  467. )
  468. cluster_id = django_filters.ModelMultipleChoiceFilter(
  469. field_name='clusters',
  470. queryset=Cluster.objects.all(),
  471. label=_('Cluster'),
  472. )
  473. tenant_group_id = django_filters.ModelMultipleChoiceFilter(
  474. field_name='tenant_groups',
  475. queryset=TenantGroup.objects.all(),
  476. label=_('Tenant group'),
  477. )
  478. tenant_group = django_filters.ModelMultipleChoiceFilter(
  479. field_name='tenant_groups__slug',
  480. queryset=TenantGroup.objects.all(),
  481. to_field_name='slug',
  482. label=_('Tenant group (slug)'),
  483. )
  484. tenant_id = django_filters.ModelMultipleChoiceFilter(
  485. field_name='tenants',
  486. queryset=Tenant.objects.all(),
  487. label=_('Tenant'),
  488. )
  489. tenant = django_filters.ModelMultipleChoiceFilter(
  490. field_name='tenants__slug',
  491. queryset=Tenant.objects.all(),
  492. to_field_name='slug',
  493. label=_('Tenant (slug)'),
  494. )
  495. tag_id = django_filters.ModelMultipleChoiceFilter(
  496. field_name='tags',
  497. queryset=Tag.objects.all(),
  498. label=_('Tag'),
  499. )
  500. tag = django_filters.ModelMultipleChoiceFilter(
  501. field_name='tags__slug',
  502. queryset=Tag.objects.all(),
  503. to_field_name='slug',
  504. label=_('Tag (slug)'),
  505. )
  506. data_source_id = django_filters.ModelMultipleChoiceFilter(
  507. queryset=DataSource.objects.all(),
  508. label=_('Data source (ID)'),
  509. )
  510. data_file_id = django_filters.ModelMultipleChoiceFilter(
  511. queryset=DataSource.objects.all(),
  512. label=_('Data file (ID)'),
  513. )
  514. class Meta:
  515. model = ConfigContext
  516. fields = ['id', 'name', 'is_active', 'data_synced', 'description']
  517. def search(self, queryset, name, value):
  518. if not value.strip():
  519. return queryset
  520. return queryset.filter(
  521. Q(name__icontains=value) |
  522. Q(description__icontains=value) |
  523. Q(data__icontains=value)
  524. )
  525. class ConfigTemplateFilterSet(BaseFilterSet):
  526. q = django_filters.CharFilter(
  527. method='search',
  528. label=_('Search'),
  529. )
  530. data_source_id = django_filters.ModelMultipleChoiceFilter(
  531. queryset=DataSource.objects.all(),
  532. label=_('Data source (ID)'),
  533. )
  534. data_file_id = django_filters.ModelMultipleChoiceFilter(
  535. queryset=DataSource.objects.all(),
  536. label=_('Data file (ID)'),
  537. )
  538. tag = TagFilter()
  539. class Meta:
  540. model = ConfigTemplate
  541. fields = ['id', 'name', 'description', 'data_synced']
  542. def search(self, queryset, name, value):
  543. if not value.strip():
  544. return queryset
  545. return queryset.filter(
  546. Q(name__icontains=value) |
  547. Q(description__icontains=value)
  548. )
  549. #
  550. # Filter for Local Config Context Data
  551. #
  552. class LocalConfigContextFilterSet(django_filters.FilterSet):
  553. local_context_data = django_filters.BooleanFilter(
  554. method='_local_context_data',
  555. label=_('Has local config context data'),
  556. )
  557. def _local_context_data(self, queryset, name, value):
  558. return queryset.exclude(local_context_data__isnull=value)
  559. class ObjectChangeFilterSet(BaseFilterSet):
  560. q = django_filters.CharFilter(
  561. method='search',
  562. label=_('Search'),
  563. )
  564. time = django_filters.DateTimeFromToRangeFilter()
  565. changed_object_type = ContentTypeFilter()
  566. changed_object_type_id = django_filters.ModelMultipleChoiceFilter(
  567. queryset=ContentType.objects.all()
  568. )
  569. user_id = django_filters.ModelMultipleChoiceFilter(
  570. queryset=get_user_model().objects.all(),
  571. label=_('User (ID)'),
  572. )
  573. user = django_filters.ModelMultipleChoiceFilter(
  574. field_name='user__username',
  575. queryset=get_user_model().objects.all(),
  576. to_field_name='username',
  577. label=_('User name'),
  578. )
  579. class Meta:
  580. model = ObjectChange
  581. fields = [
  582. 'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
  583. 'object_repr',
  584. ]
  585. def search(self, queryset, name, value):
  586. if not value.strip():
  587. return queryset
  588. return queryset.filter(
  589. Q(user_name__icontains=value) |
  590. Q(object_repr__icontains=value)
  591. )
  592. #
  593. # ContentTypes
  594. #
  595. class ObjectTypeFilterSet(django_filters.FilterSet):
  596. q = django_filters.CharFilter(
  597. method='search',
  598. label=_('Search'),
  599. )
  600. class Meta:
  601. model = ObjectType
  602. fields = ['id', 'app_label', 'model']
  603. def search(self, queryset, name, value):
  604. if not value.strip():
  605. return queryset
  606. return queryset.filter(
  607. Q(app_label__icontains=value) |
  608. Q(model__icontains=value)
  609. )