filtersets.py 20 KB

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