Coverage for extras/graphql/filters.py: 85%
223 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from typing import TYPE_CHECKING, Annotated
3import strawberry
4import strawberry_django
5from django.db.models import Q, QuerySet
6from strawberry.scalars import ID
7from strawberry_django import BaseFilterLookup, DatetimeFilterLookup, FilterLookup, StrFilterLookup
9from extras import models
10from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin
11from netbox.graphql.filter_mixins import SyncedDataFilterMixin
12from netbox.graphql.filters import BaseModelFilter, ChangeLoggedModelFilter, PrimaryModelFilter, register_filter
14if TYPE_CHECKING: 14 ↛ 15line 14 didn't jump to line 15 because the condition on line 14 was never true
15 from core.graphql.filters import ContentTypeFilter
16 from dcim.graphql.filters import (
17 DeviceRoleFilter,
18 DeviceTypeFilter,
19 LocationFilter,
20 PlatformFilter,
21 RegionFilter,
22 SiteFilter,
23 SiteGroupFilter,
24 )
25 from extras.graphql.filter_lookups import ExtraChoicesLookup
26 from netbox.graphql.enums import ColorEnum
27 from netbox.graphql.filter_lookups import (
28 BigIntegerLookup,
29 FloatLookup,
30 IntegerLookup,
31 JSONFilter,
32 StringArrayLookup,
33 TreeNodeFilter,
34 )
35 from tenancy.graphql.filters import TenantFilter, TenantGroupFilter
36 from users.graphql.filters import GroupFilter, UserFilter
37 from virtualization.graphql.filters import ClusterFilter, ClusterGroupFilter, ClusterTypeFilter
39 from .enums import *
41__all__ = (
42 'ConfigContextFilter',
43 'ConfigContextProfileFilter',
44 'ConfigTemplateFilter',
45 'CustomFieldChoiceSetFilter',
46 'CustomFieldFilter',
47 'CustomLinkFilter',
48 'EventRuleFilter',
49 'ExportTemplateFilter',
50 'ImageAttachmentFilter',
51 'JournalEntryFilter',
52 'NotificationFilter',
53 'NotificationGroupFilter',
54 'SavedFilterFilter',
55 'SubscriptionFilter',
56 'TableConfigFilter',
57 'TagFilter',
58 'WebhookFilter',
59)
62@register_filter(models.ConfigContext, lookups=True)
63class ConfigContextFilter(SyncedDataFilterMixin, ChangeLoggedModelFilter):
64 name: StrFilterLookup | None = strawberry_django.filter_field()
65 weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
66 strawberry_django.filter_field()
67 )
68 description: StrFilterLookup | None = strawberry_django.filter_field()
69 is_active: FilterLookup[bool] | None = strawberry_django.filter_field()
70 regions: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
71 strawberry_django.filter_field()
72 )
73 region_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
74 strawberry_django.filter_field()
75 )
76 site_groups: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
77 strawberry_django.filter_field()
78 )
79 site_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
80 strawberry_django.filter_field()
81 )
82 sites: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
83 locations: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
84 strawberry_django.filter_field()
85 )
86 device_types: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
87 strawberry_django.filter_field()
88 )
89 roles: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
90 strawberry_django.filter_field()
91 )
92 platforms: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
93 strawberry_django.filter_field()
94 )
95 cluster_types: Annotated['ClusterTypeFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
96 strawberry_django.filter_field()
97 )
98 cluster_groups: Annotated['ClusterGroupFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
99 strawberry_django.filter_field()
100 )
101 clusters: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
102 strawberry_django.filter_field()
103 )
104 tenant_groups: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
105 strawberry_django.filter_field()
106 )
107 tenant_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
108 strawberry_django.filter_field()
109 )
110 tenants: Annotated['TenantFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
111 strawberry_django.filter_field()
112 )
113 tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field()
114 data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
115 strawberry_django.filter_field()
116 )
119@register_filter(models.ConfigContextProfile, lookups=True)
120class ConfigContextProfileFilter(SyncedDataFilterMixin, PrimaryModelFilter):
121 name: StrFilterLookup | None = strawberry_django.filter_field()
122 description: StrFilterLookup | None = strawberry_django.filter_field()
123 tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field()
126@register_filter(models.ConfigTemplate, lookups=True)
127class ConfigTemplateFilter(SyncedDataFilterMixin, ChangeLoggedModelFilter):
128 name: StrFilterLookup | None = strawberry_django.filter_field()
129 description: StrFilterLookup | None = strawberry_django.filter_field()
130 template_code: StrFilterLookup | None = strawberry_django.filter_field()
131 environment_params: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
132 strawberry_django.filter_field()
133 )
134 mime_type: StrFilterLookup | None = strawberry_django.filter_field()
135 file_name: StrFilterLookup | None = strawberry_django.filter_field()
136 file_extension: StrFilterLookup | None = strawberry_django.filter_field()
137 as_attachment: FilterLookup[bool] | None = strawberry_django.filter_field()
140@register_filter(models.CustomField, lookups=True)
141class CustomFieldFilter(ChangeLoggedModelFilter):
142 type: BaseFilterLookup[Annotated['CustomFieldTypeEnum', strawberry.lazy('extras.graphql.enums')]] | None = (
143 strawberry_django.filter_field()
144 )
145 object_types: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
146 strawberry_django.filter_field()
147 )
148 related_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
149 strawberry_django.filter_field()
150 )
151 name: StrFilterLookup | None = strawberry_django.filter_field()
152 status: BaseFilterLookup[Annotated['CustomFieldStatusEnum', strawberry.lazy('extras.graphql.enums')]] | None = (
153 strawberry_django.filter_field()
154 )
155 label: StrFilterLookup | None = strawberry_django.filter_field()
156 group_name: StrFilterLookup | None = strawberry_django.filter_field()
157 description: StrFilterLookup | None = strawberry_django.filter_field()
158 required: FilterLookup[bool] | None = strawberry_django.filter_field()
159 unique: FilterLookup[bool] | None = strawberry_django.filter_field()
160 search_weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
161 strawberry_django.filter_field()
162 )
163 filter_logic: (
164 BaseFilterLookup[Annotated['CustomFieldFilterLogicEnum', strawberry.lazy('extras.graphql.enums')]] | None
165 ) = (
166 strawberry_django.filter_field()
167 )
168 default: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
169 strawberry_django.filter_field()
170 )
171 related_object_filter: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
172 strawberry_django.filter_field()
173 )
174 weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
175 strawberry_django.filter_field()
176 )
177 validation_minimum: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
178 strawberry_django.filter_field()
179 )
180 validation_maximum: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
181 strawberry_django.filter_field()
182 )
183 validation_regex: StrFilterLookup | None = strawberry_django.filter_field()
184 choice_set: Annotated['CustomFieldChoiceSetFilter', strawberry.lazy('extras.graphql.filters')] | None = (
185 strawberry_django.filter_field()
186 )
187 choice_set_id: ID | None = strawberry_django.filter_field()
188 ui_visible: (
189 BaseFilterLookup[Annotated['CustomFieldUIVisibleEnum', strawberry.lazy('extras.graphql.enums')]] | None
190 ) = (
191 strawberry_django.filter_field()
192 )
193 ui_editable: (
194 BaseFilterLookup[Annotated['CustomFieldUIEditableEnum', strawberry.lazy('extras.graphql.enums')]] | None
195 ) = (
196 strawberry_django.filter_field()
197 )
198 is_cloneable: FilterLookup[bool] | None = strawberry_django.filter_field()
199 nulls_first: FilterLookup[bool] | None = strawberry_django.filter_field()
200 comments: StrFilterLookup | None = strawberry_django.filter_field()
203@register_filter(models.CustomFieldChoiceSet, lookups=True)
204class CustomFieldChoiceSetFilter(ChangeLoggedModelFilter):
205 name: StrFilterLookup | None = strawberry_django.filter_field()
206 description: StrFilterLookup | None = strawberry_django.filter_field()
207 base_choices: (
208 BaseFilterLookup[Annotated['CustomFieldChoiceSetBaseEnum', strawberry.lazy('extras.graphql.enums')]] | None
209 ) = (
210 strawberry_django.filter_field()
211 )
212 extra_choices: Annotated['ExtraChoicesLookup', strawberry.lazy('extras.graphql.filter_lookups')] | None = (
213 strawberry_django.filter_field()
214 )
215 order_alphabetically: FilterLookup[bool] | None = strawberry_django.filter_field()
217 @strawberry_django.filter_field(resolve_value=True)
218 def choice_colors(
219 self,
220 queryset: QuerySet,
221 value: list[Annotated['CustomFieldChoiceColorEnum', strawberry.lazy('extras.graphql.enums')]],
222 prefix: str,
223 ) -> tuple[QuerySet, Q]:
224 if not value:
225 return queryset, Q()
227 field_name = f'{prefix}choice_colors'
228 choice_values = set()
230 for mapping in queryset.exclude(**{f'{field_name}__isnull': True}).values_list(field_name, flat=True):
231 if isinstance(mapping, dict):
232 choice_values.update(mapping.keys())
234 if not choice_values:
235 return queryset, Q(pk__in=[])
237 params = Q()
238 for color in value:
239 for choice_value in choice_values:
240 params |= Q(**{f'{field_name}__contains': {choice_value: color}})
242 return queryset, params
245@register_filter(models.CustomLink, lookups=True)
246class CustomLinkFilter(ChangeLoggedModelFilter):
247 name: StrFilterLookup | None = strawberry_django.filter_field()
248 enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
249 link_text: StrFilterLookup | None = strawberry_django.filter_field()
250 link_url: StrFilterLookup | None = strawberry_django.filter_field()
251 weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
252 strawberry_django.filter_field()
253 )
254 group_name: StrFilterLookup | None = strawberry_django.filter_field()
255 button_class: (
256 BaseFilterLookup[Annotated['CustomLinkButtonClassEnum', strawberry.lazy('extras.graphql.enums')]] | None
257 ) = (
258 strawberry_django.filter_field()
259 )
260 new_window: FilterLookup[bool] | None = strawberry_django.filter_field()
263@register_filter(models.ExportTemplate, lookups=True)
264class ExportTemplateFilter(SyncedDataFilterMixin, ChangeLoggedModelFilter):
265 name: StrFilterLookup | None = strawberry_django.filter_field()
266 description: StrFilterLookup | None = strawberry_django.filter_field()
267 template_code: StrFilterLookup | None = strawberry_django.filter_field()
268 environment_params: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
269 strawberry_django.filter_field()
270 )
271 mime_type: StrFilterLookup | None = strawberry_django.filter_field()
272 file_name: StrFilterLookup | None = strawberry_django.filter_field()
273 file_extension: StrFilterLookup | None = strawberry_django.filter_field()
274 as_attachment: FilterLookup[bool] | None = strawberry_django.filter_field()
277@register_filter(models.ImageAttachment, lookups=True)
278class ImageAttachmentFilter(ChangeLoggedModelFilter):
279 object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
280 strawberry_django.filter_field()
281 )
282 object_id: ID | None = strawberry_django.filter_field()
283 image_height: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
284 strawberry_django.filter_field()
285 )
286 image_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
287 strawberry_django.filter_field()
288 )
289 image_size: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
290 strawberry_django.filter_field()
291 )
292 name: StrFilterLookup | None = strawberry_django.filter_field()
295@register_filter(models.JournalEntry, lookups=True)
296class JournalEntryFilter(CustomFieldsFilterMixin, TagsFilterMixin, ChangeLoggedModelFilter):
297 assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
298 strawberry_django.filter_field()
299 )
300 assigned_object_type_id: ID | None = strawberry_django.filter_field()
301 assigned_object_id: ID | None = strawberry_django.filter_field()
302 created_by: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = (
303 strawberry_django.filter_field()
304 )
305 kind: BaseFilterLookup[Annotated['JournalEntryKindEnum', strawberry.lazy('extras.graphql.enums')]] | None = (
306 strawberry_django.filter_field()
307 )
308 comments: StrFilterLookup | None = strawberry_django.filter_field()
311@register_filter(models.Notification, lookups=True)
312class NotificationFilter(BaseModelFilter):
313 created: DatetimeFilterLookup | None = strawberry_django.filter_field()
314 read: DatetimeFilterLookup | None = strawberry_django.filter_field()
315 user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
316 user_id: ID | None = strawberry_django.filter_field()
317 object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
318 strawberry_django.filter_field()
319 )
320 object_type_id: ID | None = strawberry_django.filter_field()
321 object_id: ID | None = strawberry_django.filter_field()
322 object_repr: StrFilterLookup | None = strawberry_django.filter_field()
323 event_type: StrFilterLookup | None = strawberry_django.filter_field()
326@register_filter(models.NotificationGroup, lookups=True)
327class NotificationGroupFilter(ChangeLoggedModelFilter):
328 name: StrFilterLookup | None = strawberry_django.filter_field()
329 description: StrFilterLookup | None = strawberry_django.filter_field()
330 groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
331 users: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
334@register_filter(models.SavedFilter, lookups=True)
335class SavedFilterFilter(ChangeLoggedModelFilter):
336 name: StrFilterLookup | None = strawberry_django.filter_field()
337 slug: StrFilterLookup | None = strawberry_django.filter_field()
338 description: StrFilterLookup | None = strawberry_django.filter_field()
339 user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
340 user_id: ID | None = strawberry_django.filter_field()
341 weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
342 strawberry_django.filter_field()
343 )
344 enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
345 shared: FilterLookup[bool] | None = strawberry_django.filter_field()
346 parameters: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
347 strawberry_django.filter_field()
348 )
351@register_filter(models.Subscription, lookups=True)
352class SubscriptionFilter(BaseModelFilter):
353 created: DatetimeFilterLookup | None = strawberry_django.filter_field()
354 user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
355 user_id: ID | None = strawberry_django.filter_field()
356 object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
357 strawberry_django.filter_field()
358 )
359 object_type_id: ID | None = strawberry_django.filter_field()
360 object_id: ID | None = strawberry_django.filter_field()
363@register_filter(models.TableConfig, lookups=True)
364class TableConfigFilter(ChangeLoggedModelFilter):
365 name: StrFilterLookup | None = strawberry_django.filter_field()
366 description: StrFilterLookup | None = strawberry_django.filter_field()
367 user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
368 user_id: ID | None = strawberry_django.filter_field()
369 weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
370 strawberry_django.filter_field()
371 )
372 enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
373 shared: FilterLookup[bool] | None = strawberry_django.filter_field()
376@register_filter(models.Tag, lookups=True)
377class TagFilter(ChangeLoggedModelFilter):
378 name: StrFilterLookup | None = strawberry_django.filter_field()
379 slug: StrFilterLookup | None = strawberry_django.filter_field()
380 color: BaseFilterLookup[Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')]] | None = (
381 strawberry_django.filter_field()
382 )
383 description: StrFilterLookup | None = strawberry_django.filter_field()
386@register_filter(models.Webhook, lookups=True)
387class WebhookFilter(CustomFieldsFilterMixin, TagsFilterMixin, ChangeLoggedModelFilter):
388 name: StrFilterLookup | None = strawberry_django.filter_field()
389 description: StrFilterLookup | None = strawberry_django.filter_field()
390 payload_url: StrFilterLookup | None = strawberry_django.filter_field()
391 http_method: (
392 BaseFilterLookup[Annotated['WebhookHttpMethodEnum', strawberry.lazy('extras.graphql.enums')]] | None
393 ) = (
394 strawberry_django.filter_field()
395 )
396 http_content_type: StrFilterLookup | None = strawberry_django.filter_field()
397 additional_headers: StrFilterLookup | None = strawberry_django.filter_field()
398 body_template: StrFilterLookup | None = strawberry_django.filter_field()
399 secret: StrFilterLookup | None = strawberry_django.filter_field()
400 ssl_verification: FilterLookup[bool] | None = strawberry_django.filter_field()
401 ca_file_path: StrFilterLookup | None = strawberry_django.filter_field()
402 timeout: FilterLookup[int] | None = strawberry_django.filter_field()
403 events: Annotated['EventRuleFilter', strawberry.lazy('extras.graphql.filters')] | None = (
404 strawberry_django.filter_field()
405 )
408@register_filter(models.EventRule, lookups=True)
409class EventRuleFilter(CustomFieldsFilterMixin, TagsFilterMixin, ChangeLoggedModelFilter):
410 name: StrFilterLookup | None = strawberry_django.filter_field()
411 description: StrFilterLookup | None = strawberry_django.filter_field()
412 event_types: Annotated['StringArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
413 strawberry_django.filter_field()
414 )
415 enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
416 conditions: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
417 strawberry_django.filter_field()
418 )
419 action_type: BaseFilterLookup[Annotated['EventRuleActionEnum', strawberry.lazy('extras.graphql.enums')]] | None = (
420 strawberry_django.filter_field()
421 )
422 action_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
423 strawberry_django.filter_field()
424 )
425 action_object_type_id: ID | None = strawberry_django.filter_field()
426 action_object_id: ID | None = strawberry_django.filter_field()
427 action_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
428 strawberry_django.filter_field()
429 )
430 comments: StrFilterLookup | None = strawberry_django.filter_field()