Closes #7598: Enable custom field filtering for GraphQL (#18701)

This commit is contained in:
Jeremy Stretch 2025-03-07 13:49:06 -05:00 committed by GitHub
parent bbf4eea76c
commit c35f5f829a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 3041 additions and 681 deletions

View File

@ -76,11 +76,13 @@ Create the following for each model:
## 13. GraphQL API components ## 13. GraphQL API components
Create a GraphQL object type for the model in `graphql/types.py` by subclassing the appropriate class from `netbox.graphql.types`. Create the following for each model:
**Note:** GraphQL unit tests may fail citing null values on a non-nullable field if related objects are prefetched. You may need to fix this by setting the type annotation to be `= strawberry_django.field(select_related=["policy"])` or similar. * GraphQL object type for the model in `graphql/types.py` (subclass the appropriate class from `netbox.graphql.types`)
* Add a GraphQL filter for the model in `graphql/filters.py`
* Extend the query class for the app in `graphql/schema.py` with the individual object and object list fields
Also extend the schema class defined in `graphql/schema.py` with the individual object and object list fields per the established convention. **Note:** GraphQL unit tests may fail citing null values on a non-nullable field if related objects are prefetched. You may need to fix this by setting the type annotation to be `= strawberry_django.field(select_related=["foo"])` or similar.
## 14. Add tests ## 14. Add tests

View File

@ -11,7 +11,7 @@ curl -H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-H "Accept: application/json" \ -H "Accept: application/json" \
http://netbox/graphql/ \ http://netbox/graphql/ \
--data '{"query": "query {circuit_list(status:\"active\") {cid provider {name}}}"}' --data '{"query": "query {circuit_list(filters:{status: STATUS_ACTIVE}) {cid provider {name}}}"}'
``` ```
The response will include the requested data formatted as JSON: The response will include the requested data formatted as JSON:
@ -51,19 +51,48 @@ For more detail on constructing GraphQL queries, see the [GraphQL queries docume
## Filtering ## Filtering
The GraphQL API employs the same filtering logic as the UI and REST API. Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only sites within the North Carolina region with a status of active: !!! note "Changed in NetBox v4.3"
The filtering syntax fo the GraphQL API has changed substantially in NetBox v4.3.
Filters can be specified as key-value pairs within parentheses immediately following the query name. For example, the following will return only active sites:
``` ```
query { query {
site_list(filters: {region: "us-nc", status: "active"}) { site_list(
filters: {
status: STATUS_ACTIVE
}
) {
name name
} }
} }
``` ```
In addition, filtering can be done on list of related objects as shown in the following query:
Filters can be combined with logical operators, such as `OR` and `NOT`. For example, the following will return every site that is planned _or_ assigned to a tenant named Foo:
``` ```
{ query {
site_list(
filters: {
status: STATUS_PLANNED,
OR: {
tenant: {
name: {
exact: "Foo"
}
}
}
}
) {
name
}
}
```
Filtering can also be applied to related objects. For example, the following query will return only enabled interfaces for each device:
```
query {
device_list { device_list {
id id
name name

View File

@ -1,6 +1,6 @@
# Filters & Filter Sets # Filters & Filter Sets
Filter sets define the mechanisms available for filtering or searching through a set of objects in NetBox. For instance, sites can be filtered by their parent region or group, status, facility ID, and so on. The same filter set is used consistently for a model whether the request is made via the UI, REST API, or GraphQL API. NetBox employs the [django-filters2](https://django-tables2.readthedocs.io/en/latest/) library to define filter sets. Filter sets define the mechanisms available for filtering or searching through a set of objects in NetBox. For instance, sites can be filtered by their parent region or group, status, facility ID, and so on. The same filter set is used consistently for a model whether the request is made via the UI or REST API. (Note that the GraphQL API uses a separate filter class.) NetBox employs the [django-filters2](https://django-tables2.readthedocs.io/en/latest/) library to define filter sets.
## FilterSet Classes ## FilterSet Classes

View File

@ -0,0 +1,20 @@
import strawberry
from circuits.choices import *
__all__ = (
'CircuitStatusEnum',
'CircuitCommitRateEnum',
'CircuitTerminationSideEnum',
'CircuitTerminationPortSpeedEnum',
'CircuitPriorityEnum',
'VirtualCircuitTerminationRoleEnum',
)
CircuitCommitRateEnum = strawberry.enum(CircuitCommitRateChoices.as_enum())
CircuitPriorityEnum = strawberry.enum(CircuitPriorityChoices.as_enum())
CircuitStatusEnum = strawberry.enum(CircuitStatusChoices.as_enum())
CircuitTerminationSideEnum = strawberry.enum(CircuitTerminationSideChoices.as_enum())
CircuitTerminationPortSpeedEnum = strawberry.enum(CircuitTerminationPortSpeedChoices.as_enum())
VirtualCircuitTerminationRoleEnum = strawberry.enum(VirtualCircuitTerminationRoleChoices.as_enum())

View File

@ -0,0 +1,19 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from netbox.graphql.filter_mixins import OrganizationalModelFilterMixin
if TYPE_CHECKING:
from netbox.graphql.enums import ColorEnum
__all__ = (
'BaseCircuitTypeFilterMixin',
)
@dataclass
class BaseCircuitTypeFilterMixin(OrganizationalModelFilterMixin):
color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()

View File

@ -1,7 +1,30 @@
import strawberry_django from datetime import date
from typing import Annotated, TYPE_CHECKING
from circuits import filtersets, models import strawberry
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup, DateFilterLookup
from circuits import models
from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin
from dcim.graphql.filter_mixins import CabledObjectModelFilterMixin
from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin
from netbox.graphql.filter_mixins import (
DistanceFilterMixin,
ImageAttachmentFilterMixin,
OrganizationalModelFilterMixin,
PrimaryModelFilterMixin,
)
from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
from .filter_mixins import BaseCircuitTypeFilterMixin
if TYPE_CHECKING:
from core.graphql.filters import ContentTypeFilter
from dcim.graphql.filters import InterfaceFilter
from ipam.graphql.filters import ASNFilter
from netbox.graphql.filter_lookups import IntegerLookup
from .enums import *
__all__ = ( __all__ = (
'CircuitFilter', 'CircuitFilter',
@ -19,66 +42,160 @@ __all__ = (
@strawberry_django.filter(models.CircuitTermination, lookups=True) @strawberry_django.filter(models.CircuitTermination, lookups=True)
@autotype_decorator(filtersets.CircuitTerminationFilterSet) class CircuitTerminationFilter(
class CircuitTerminationFilter(BaseFilterMixin): BaseObjectTypeFilterMixin,
pass CustomFieldsFilterMixin,
TagsFilterMixin,
ChangeLogFilterMixin,
CabledObjectModelFilterMixin,
):
circuit: Annotated['CircuitFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
term_side: Annotated['CircuitTerminationSideEnum', strawberry.lazy('circuits.graphql.enums')] | None = (
strawberry_django.filter_field()
)
termination_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
termination_id: ID | None = strawberry_django.filter_field()
port_speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
upstream_speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
xconnect_id: FilterLookup[str] | None = strawberry_django.filter_field()
pp_info: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.Circuit, lookups=True) @strawberry_django.filter(models.Circuit, lookups=True)
@autotype_decorator(filtersets.CircuitFilterSet) class CircuitFilter(
class CircuitFilter(BaseFilterMixin): ContactFilterMixin,
pass ImageAttachmentFilterMixin,
DistanceFilterMixin,
TenancyFilterMixin,
PrimaryModelFilterMixin
):
cid: FilterLookup[str] | None = strawberry_django.filter_field()
provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
provider_id: ID | None = strawberry_django.filter_field()
provider_account: Annotated['ProviderAccountFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
provider_account_id: ID | None = strawberry_django.filter_field()
type: Annotated['CircuitTypeFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
type_id: ID | None = strawberry_django.filter_field()
status: Annotated['CircuitStatusEnum', strawberry.lazy('circuits.graphql.enums')] | None = (
strawberry_django.filter_field()
)
install_date: DateFilterLookup[date] | None = strawberry_django.filter_field()
termination_date: DateFilterLookup[date] | None = strawberry_django.filter_field()
commit_rate: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.CircuitType, lookups=True) @strawberry_django.filter(models.CircuitType, lookups=True)
@autotype_decorator(filtersets.CircuitTypeFilterSet) class CircuitTypeFilter(BaseCircuitTypeFilterMixin):
class CircuitTypeFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.CircuitGroup, lookups=True) @strawberry_django.filter(models.CircuitGroup, lookups=True)
@autotype_decorator(filtersets.CircuitGroupFilterSet) class CircuitGroupFilter(TenancyFilterMixin, OrganizationalModelFilterMixin):
class CircuitGroupFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.CircuitGroupAssignment, lookups=True) @strawberry_django.filter(models.CircuitGroupAssignment, lookups=True)
@autotype_decorator(filtersets.CircuitGroupAssignmentFilterSet) class CircuitGroupAssignmentFilter(
class CircuitGroupAssignmentFilter(BaseFilterMixin): BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin
pass ):
member_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
member_id: ID | None = strawberry_django.filter_field()
group: Annotated['CircuitGroupFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
priority: Annotated['CircuitPriorityEnum', strawberry.lazy('circuits.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Provider, lookups=True) @strawberry_django.filter(models.Provider, lookups=True)
@autotype_decorator(filtersets.ProviderFilterSet) class ProviderFilter(ContactFilterMixin, PrimaryModelFilterMixin):
class ProviderFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
asns: Annotated['ASNFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ProviderAccount, lookups=True) @strawberry_django.filter(models.ProviderAccount, lookups=True)
@autotype_decorator(filtersets.ProviderAccountFilterSet) class ProviderAccountFilter(ContactFilterMixin, PrimaryModelFilterMixin):
class ProviderAccountFilter(BaseFilterMixin): provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
provider_id: ID | None = strawberry_django.filter_field()
account: FilterLookup[str] | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ProviderNetwork, lookups=True) @strawberry_django.filter(models.ProviderNetwork, lookups=True)
@autotype_decorator(filtersets.ProviderNetworkFilterSet) class ProviderNetworkFilter(PrimaryModelFilterMixin):
class ProviderNetworkFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass provider: Annotated['ProviderFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
provider_id: ID | None = strawberry_django.filter_field()
service_id: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.VirtualCircuitType, lookups=True) @strawberry_django.filter(models.VirtualCircuitType, lookups=True)
@autotype_decorator(filtersets.VirtualCircuitTypeFilterSet) class VirtualCircuitTypeFilter(BaseCircuitTypeFilterMixin):
class VirtualCircuitTypeFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.VirtualCircuit, lookups=True) @strawberry_django.filter(models.VirtualCircuit, lookups=True)
@autotype_decorator(filtersets.VirtualCircuitFilterSet) class VirtualCircuitFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class VirtualCircuitFilter(BaseFilterMixin): cid: FilterLookup[str] | None = strawberry_django.filter_field()
pass provider_network: Annotated['ProviderNetworkFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
provider_network_id: ID | None = strawberry_django.filter_field()
provider_account: Annotated['ProviderAccountFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
provider_account_id: ID | None = strawberry_django.filter_field()
type: Annotated['VirtualCircuitTypeFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
type_id: ID | None = strawberry_django.filter_field()
status: Annotated['CircuitStatusEnum', strawberry.lazy('circuits.graphql.enums')] | None = (
strawberry_django.filter_field()
)
group_assignments: Annotated['CircuitGroupAssignmentFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VirtualCircuitTermination, lookups=True) @strawberry_django.filter(models.VirtualCircuitTermination, lookups=True)
@autotype_decorator(filtersets.VirtualCircuitTerminationFilterSet) class VirtualCircuitTerminationFilter(
class VirtualCircuitTerminationFilter(BaseFilterMixin): BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin
pass ):
virtual_circuit: Annotated['VirtualCircuitFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
virtual_circuit_id: ID | None = strawberry_django.filter_field()
role: Annotated['VirtualCircuitTerminationRoleEnum', strawberry.lazy('circuits.graphql.enums')] | None = (
strawberry_django.filter_field()
)
interface: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
interface_id: ID | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -10,11 +10,15 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, ObjectType, O
from tenancy.graphql.types import TenantType from tenancy.graphql.types import TenantType
from .filters import * from .filters import *
if TYPE_CHECKING:
from dcim.graphql.types import InterfaceType, LocationType, RegionType, SiteGroupType, SiteType
from ipam.graphql.types import ASNType
__all__ = ( __all__ = (
'CircuitTerminationType',
'CircuitType',
'CircuitGroupAssignmentType', 'CircuitGroupAssignmentType',
'CircuitGroupType', 'CircuitGroupType',
'CircuitTerminationType',
'CircuitType',
'CircuitTypeType', 'CircuitTypeType',
'ProviderType', 'ProviderType',
'ProviderAccountType', 'ProviderAccountType',
@ -62,7 +66,7 @@ class ProviderNetworkType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.CircuitTermination, models.CircuitTermination,
exclude=('termination_type', 'termination_id', '_location', '_region', '_site', '_site_group', '_provider_network'), exclude=['termination_type', 'termination_id', '_location', '_region', '_site', '_site_group', '_provider_network'],
filters=CircuitTerminationFilter filters=CircuitTerminationFilter
) )
class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, ObjectType): class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, ObjectType):
@ -117,7 +121,7 @@ class CircuitGroupType(OrganizationalObjectType):
@strawberry_django.type( @strawberry_django.type(
models.CircuitGroupAssignment, models.CircuitGroupAssignment,
exclude=('member_type', 'member_id'), exclude=['member_type', 'member_id'],
filters=CircuitGroupAssignmentFilter filters=CircuitGroupAssignmentFilter
) )
class CircuitGroupAssignmentType(TagsMixin, BaseObjectType): class CircuitGroupAssignmentType(TagsMixin, BaseObjectType):

View File

@ -0,0 +1,36 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry import ID
from strawberry_django import DatetimeFilterLookup
if TYPE_CHECKING:
from .filters import *
__all__ = (
'BaseFilterMixin',
'BaseObjectTypeFilterMixin',
'ChangeLogFilterMixin',
)
# @strawberry.input
class BaseFilterMixin: ...
@dataclass
class BaseObjectTypeFilterMixin(BaseFilterMixin):
id: ID | None = strawberry.UNSET
@dataclass
class ChangeLogFilterMixin(BaseFilterMixin):
id: ID | None = strawberry.UNSET
changelog: Annotated['ObjectChangeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
last_updated: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()

View File

@ -1,28 +1,89 @@
import strawberry_django from datetime import datetime
from typing import Annotated, TYPE_CHECKING
from core import filtersets, models import strawberry
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry_django
from django.contrib.contenttypes.models import ContentType as DjangoContentType
from strawberry.scalars import ID
from strawberry_django import DatetimeFilterLookup, FilterLookup
from core import models
from core.graphql.filter_mixins import BaseFilterMixin
from netbox.graphql.filter_mixins import PrimaryModelFilterMixin
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import IntegerLookup, JSONFilter
from users.graphql.filters import UserFilter
__all__ = ( __all__ = (
'DataFileFilter', 'DataFileFilter',
'DataSourceFilter', 'DataSourceFilter',
'ObjectChangeFilter', 'ObjectChangeFilter',
'ContentTypeFilter',
) )
@strawberry_django.filter(models.DataFile, lookups=True) @strawberry_django.filter(models.DataFile, lookups=True)
@autotype_decorator(filtersets.DataFileFilterSet)
class DataFileFilter(BaseFilterMixin): class DataFileFilter(BaseFilterMixin):
pass id: ID | None = strawberry_django.filter_field()
created: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
last_updated: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
source: Annotated['DataSourceFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
source_id: ID | None = strawberry_django.filter_field()
path: FilterLookup[str] | None = strawberry_django.filter_field()
size: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
hash: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.DataSource, lookups=True) @strawberry_django.filter(models.DataSource, lookups=True)
@autotype_decorator(filtersets.DataSourceFilterSet) class DataSourceFilter(PrimaryModelFilterMixin):
class DataSourceFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass type: FilterLookup[str] | None = strawberry_django.filter_field()
source_url: FilterLookup[str] | None = strawberry_django.filter_field()
status: FilterLookup[str] | None = strawberry_django.filter_field()
enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
ignore_rules: FilterLookup[str] | None = strawberry_django.filter_field()
parameters: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
last_synced: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
datafiles: Annotated['DataFileFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ObjectChange, lookups=True) @strawberry_django.filter(models.ObjectChange, lookups=True)
@autotype_decorator(filtersets.ObjectChangeFilterSet)
class ObjectChangeFilter(BaseFilterMixin): class ObjectChangeFilter(BaseFilterMixin):
pass id: ID | None = strawberry_django.filter_field()
time: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
user_name: FilterLookup[str] | None = strawberry_django.filter_field()
request_id: FilterLookup[str] | None = strawberry_django.filter_field()
action: FilterLookup[str] | None = strawberry_django.filter_field()
changed_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
changed_object_type_id: ID | None = strawberry_django.filter_field()
changed_object_id: ID | None = strawberry_django.filter_field()
related_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
related_object_id: ID | None = strawberry_django.filter_field()
object_repr: FilterLookup[str] | None = strawberry_django.filter_field()
prechange_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
postchange_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(DjangoContentType, lookups=True)
class ContentTypeFilter(BaseFilterMixin):
id: ID | None = strawberry_django.filter_field()
app_label: FilterLookup[str] | None = strawberry_django.filter_field()
model: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,4 +1,4 @@
from typing import Annotated, List from typing import Annotated, List, TYPE_CHECKING
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -6,6 +6,9 @@ from django.contrib.contenttypes.models import ContentType
from core.models import ObjectChange from core.models import ObjectChange
if TYPE_CHECKING:
from netbox.core.graphql.types import ObjectChangeType
__all__ = ( __all__ = (
'ChangelogMixin', 'ChangelogMixin',
) )

View File

@ -2,12 +2,14 @@ from typing import Annotated, List
import strawberry import strawberry
import strawberry_django import strawberry_django
from django.contrib.contenttypes.models import ContentType as DjangoContentType
from core import models from core import models
from netbox.graphql.types import BaseObjectType, NetBoxObjectType from netbox.graphql.types import BaseObjectType, NetBoxObjectType
from .filters import * from .filters import *
__all__ = ( __all__ = (
'ContentType',
'DataFileType', 'DataFileType',
'DataSourceType', 'DataSourceType',
'ObjectChangeType', 'ObjectChangeType',
@ -40,3 +42,8 @@ class DataSourceType(NetBoxObjectType):
) )
class ObjectChangeType(BaseObjectType): class ObjectChangeType(BaseObjectType):
pass pass
@strawberry_django.type(DjangoContentType, fields='__all__')
class ContentType:
pass

View File

@ -0,0 +1,77 @@
import strawberry
from dcim.choices import *
__all__ = (
'CableEndEnum',
'CableLengthUnitEnum',
'CableTypeEnum',
'ConsolePortSpeedEnum',
'ConsolePortTypeEnum',
'DeviceAirflowEnum',
'DeviceFaceEnum',
'DeviceStatusEnum',
'InterfaceDuplexEnum',
'InterfaceModeEnum',
'InterfacePoEModeEnum',
'InterfacePoETypeEnum',
'InterfaceSpeedEnum',
'InterfaceTypeEnum',
'InventoryItemStatusEnum',
'LinkStatusEnum',
'LocationStatusEnum',
'ModuleAirflowEnum',
'ModuleStatusEnum',
'PortTypeEnum',
'PowerFeedPhaseEnum',
'PowerFeedStatusEnum',
'PowerFeedSupplyEnum',
'PowerFeedTypeEnum',
'PowerOutletFeedLegEnum',
'PowerOutletTypeEnum',
'PowerPortTypeEnum',
'RackAirflowEnum',
'RackDimensionUnitEnum',
'RackFormFactorEnum',
'RackStatusEnum',
'RackWidthEnum',
'SiteStatusEnum',
'SubdeviceRoleEnum',
'VirtualDeviceContextStatusEnum',
)
CableEndEnum = strawberry.enum(CableEndChoices.as_enum())
CableLengthUnitEnum = strawberry.enum(CableLengthUnitChoices.as_enum())
CableTypeEnum = strawberry.enum(CableTypeChoices.as_enum())
ConsolePortSpeedEnum = strawberry.enum(ConsolePortSpeedChoices.as_enum())
ConsolePortTypeEnum = strawberry.enum(ConsolePortTypeChoices.as_enum())
DeviceAirflowEnum = strawberry.enum(DeviceAirflowChoices.as_enum())
DeviceFaceEnum = strawberry.enum(DeviceFaceChoices.as_enum())
DeviceStatusEnum = strawberry.enum(DeviceStatusChoices.as_enum())
InterfaceDuplexEnum = strawberry.enum(InterfaceDuplexChoices.as_enum())
InterfaceModeEnum = strawberry.enum(InterfaceModeChoices.as_enum())
InterfacePoEModeEnum = strawberry.enum(InterfacePoEModeChoices.as_enum())
InterfacePoETypeEnum = strawberry.enum(InterfacePoETypeChoices.as_enum())
InterfaceSpeedEnum = strawberry.enum(InterfaceSpeedChoices.as_enum())
InterfaceTypeEnum = strawberry.enum(InterfaceTypeChoices.as_enum())
InventoryItemStatusEnum = strawberry.enum(InventoryItemStatusChoices.as_enum())
LinkStatusEnum = strawberry.enum(LinkStatusChoices.as_enum())
LocationStatusEnum = strawberry.enum(LocationStatusChoices.as_enum())
ModuleAirflowEnum = strawberry.enum(ModuleAirflowChoices.as_enum())
ModuleStatusEnum = strawberry.enum(ModuleStatusChoices.as_enum())
PortTypeEnum = strawberry.enum(PortTypeChoices.as_enum())
PowerFeedPhaseEnum = strawberry.enum(PowerFeedPhaseChoices.as_enum())
PowerFeedStatusEnum = strawberry.enum(PowerFeedStatusChoices.as_enum())
PowerFeedSupplyEnum = strawberry.enum(PowerFeedSupplyChoices.as_enum())
PowerFeedTypeEnum = strawberry.enum(PowerFeedTypeChoices.as_enum())
PowerOutletFeedLegEnum = strawberry.enum(PowerOutletFeedLegChoices.as_enum())
PowerOutletTypeEnum = strawberry.enum(PowerOutletTypeChoices.as_enum())
PowerPortTypeEnum = strawberry.enum(PowerPortTypeChoices.as_enum())
RackAirflowEnum = strawberry.enum(RackAirflowChoices.as_enum())
RackDimensionUnitEnum = strawberry.enum(RackDimensionUnitChoices.as_enum())
RackFormFactorEnum = strawberry.enum(RackFormFactorChoices.as_enum())
RackStatusEnum = strawberry.enum(RackStatusChoices.as_enum())
RackWidthEnum = strawberry.enum(RackWidthChoices.as_enum())
SiteStatusEnum = strawberry.enum(SiteStatusChoices.as_enum())
SubdeviceRoleEnum = strawberry.enum(SubdeviceRoleChoices.as_enum())
VirtualDeviceContextStatusEnum = strawberry.enum(VirtualDeviceContextStatusChoices.as_enum())

View File

@ -0,0 +1,149 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry import ID
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import BaseFilterMixin, ChangeLogFilterMixin
from core.graphql.filters import ContentTypeFilter
from netbox.graphql.filter_mixins import NetBoxModelFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin
from .enums import *
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import IntegerLookup
from extras.graphql.filters import ConfigTemplateFilter
from ipam.graphql.filters import VLANFilter, VLANTranslationPolicyFilter
from .filters import *
__all__ = (
'CabledObjectModelFilterMixin',
'ComponentModelFilterMixin',
'ComponentTemplateFilterMixin',
'InterfaceBaseFilterMixin',
'ModularComponentModelFilterMixin',
'ModularComponentTemplateFilterMixin',
'RackBaseFilterMixin',
'RenderConfigFilterMixin',
'ScopedFilterMixin',
)
@dataclass
class ScopedFilterMixin(BaseFilterMixin):
scope_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
scope_id: ID | None = strawberry_django.filter_field()
@dataclass
class ComponentModelFilterMixin(NetBoxModelFilterMixin):
device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
device_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
label: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
@dataclass
class ModularComponentModelFilterMixin(ComponentModelFilterMixin):
module: Annotated['ModuleFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
module_id: ID | None = strawberry_django.filter_field()
inventory_items: Annotated['InventoryItemFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@dataclass
class CabledObjectModelFilterMixin(BaseFilterMixin):
cable: Annotated['CableFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
cable_id: ID | None = strawberry_django.filter_field()
cable_end: CableEndEnum | None = strawberry_django.filter_field()
mark_connected: FilterLookup[bool] | None = strawberry_django.filter_field()
@dataclass
class ComponentTemplateFilterMixin(ChangeLogFilterMixin):
device_type: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
device_type_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
label: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
@dataclass
class ModularComponentTemplateFilterMixin(ComponentTemplateFilterMixin):
module_type: Annotated['ModuleTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@dataclass
class RenderConfigFilterMixin(BaseFilterMixin):
config_template: Annotated['ConfigTemplateFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
config_template_id: ID | None = strawberry_django.filter_field()
@dataclass
class InterfaceBaseFilterMixin(BaseFilterMixin):
enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
mtu: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
mode: InterfaceModeEnum | None = strawberry_django.filter_field()
parent: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
parent_id: ID | None = strawberry_django.filter_field()
bridge: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
bridge_id: ID | None = strawberry_django.filter_field()
untagged_vlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tagged_vlans: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
qinq_svlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
vlan_translation_policy: Annotated['VLANTranslationPolicyFilter', strawberry.lazy('ipam.graphql.filters')] | None \
= strawberry_django.filter_field()
primary_mac_address: Annotated['MACAddressFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_mac_address_id: ID | None = strawberry_django.filter_field()
@dataclass
class RackBaseFilterMixin(WeightFilterMixin, PrimaryModelFilterMixin):
width: Annotated['RackWidthEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
u_height: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
starting_unit: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
desc_units: FilterLookup[bool] | None = strawberry_django.filter_field()
outer_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
outer_depth: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
outer_unit: Annotated['RackDimensionUnitEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
mounting_depth: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
max_weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,7 +1,46 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from dcim import filtersets, models import strawberry
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import ChangeLogFilterMixin
from dcim import models
from extras.graphql.filter_mixins import ConfigContextFilterMixin
from netbox.graphql.filter_mixins import (
PrimaryModelFilterMixin,
OrganizationalModelFilterMixin,
NestedGroupModelFilterMixin,
ImageAttachmentFilterMixin,
WeightFilterMixin,
)
from tenancy.graphql.filter_mixins import TenancyFilterMixin, ContactFilterMixin
from .filter_mixins import (
CabledObjectModelFilterMixin,
ComponentModelFilterMixin,
ComponentTemplateFilterMixin,
InterfaceBaseFilterMixin,
ModularComponentModelFilterMixin,
ModularComponentTemplateFilterMixin,
RackBaseFilterMixin,
RenderConfigFilterMixin,
)
if TYPE_CHECKING:
from core.graphql.filters import ContentTypeFilter
from extras.graphql.filters import ConfigTemplateFilter, ImageAttachmentFilter
from ipam.graphql.filters import (
ASNFilter, FHRPGroupAssignmentFilter, IPAddressFilter, PrefixFilter, VLANGroupFilter, VRFFilter,
)
from netbox.graphql.enums import ColorEnum
from netbox.graphql.filter_lookups import FloatLookup, IntegerArrayLookup, IntegerLookup, TreeNodeFilter
from users.graphql.filters import UserFilter
from virtualization.graphql.filters import ClusterFilter
from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter
from wireless.graphql.enums import WirelessChannelEnum, WirelessRoleEnum
from wireless.graphql.filters import WirelessLANFilter, WirelessLinkFilter
from .enums import *
__all__ = ( __all__ = (
'CableFilter', 'CableFilter',
@ -13,7 +52,6 @@ __all__ = (
'DeviceFilter', 'DeviceFilter',
'DeviceBayFilter', 'DeviceBayFilter',
'DeviceBayTemplateFilter', 'DeviceBayTemplateFilter',
'InventoryItemTemplateFilter',
'DeviceRoleFilter', 'DeviceRoleFilter',
'DeviceTypeFilter', 'DeviceTypeFilter',
'FrontPortFilter', 'FrontPortFilter',
@ -22,6 +60,7 @@ __all__ = (
'InterfaceTemplateFilter', 'InterfaceTemplateFilter',
'InventoryItemFilter', 'InventoryItemFilter',
'InventoryItemRoleFilter', 'InventoryItemRoleFilter',
'InventoryItemTemplateFilter',
'LocationFilter', 'LocationFilter',
'MACAddressFilter', 'MACAddressFilter',
'ManufacturerFilter', 'ManufacturerFilter',
@ -51,258 +90,763 @@ __all__ = (
@strawberry_django.filter(models.Cable, lookups=True) @strawberry_django.filter(models.Cable, lookups=True)
@autotype_decorator(filtersets.CableFilterSet) class CableFilter(PrimaryModelFilterMixin, TenancyFilterMixin):
class CableFilter(BaseFilterMixin): type: Annotated['CableTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
pass status: Annotated['LinkStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
label: FilterLookup[str] | None = strawberry_django.filter_field()
color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
length: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
length_unit: Annotated['CableLengthUnitEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
terminations: Annotated['CableTerminationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.CableTermination, lookups=True) @strawberry_django.filter(models.CableTermination, lookups=True)
@autotype_decorator(filtersets.CableTerminationFilterSet) class CableTerminationFilter(ChangeLogFilterMixin):
class CableTerminationFilter(BaseFilterMixin): cable: Annotated['CableFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass cable_id: ID | None = strawberry_django.filter_field()
cable_end: Annotated['CableEndEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
termination_type: Annotated['CableTerminationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
termination_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ConsolePort, lookups=True) @strawberry_django.filter(models.ConsolePort, lookups=True)
@autotype_decorator(filtersets.ConsolePortFilterSet) class ConsolePortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class ConsolePortFilter(BaseFilterMixin): type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
speed: Annotated['ConsolePortSpeedEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ConsolePortTemplate, lookups=True) @strawberry_django.filter(models.ConsolePortTemplate, lookups=True)
@autotype_decorator(filtersets.ConsolePortTemplateFilterSet) class ConsolePortTemplateFilter(ModularComponentTemplateFilterMixin):
class ConsolePortTemplateFilter(BaseFilterMixin): type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.ConsoleServerPort, lookups=True) @strawberry_django.filter(models.ConsoleServerPort, lookups=True)
@autotype_decorator(filtersets.ConsoleServerPortFilterSet) class ConsoleServerPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class ConsoleServerPortFilter(BaseFilterMixin): type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
speed: Annotated['ConsolePortSpeedEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ConsoleServerPortTemplate, lookups=True) @strawberry_django.filter(models.ConsoleServerPortTemplate, lookups=True)
@autotype_decorator(filtersets.ConsoleServerPortTemplateFilterSet) class ConsoleServerPortTemplateFilter(ModularComponentTemplateFilterMixin):
class ConsoleServerPortTemplateFilter(BaseFilterMixin): type: Annotated['ConsolePortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.Device, lookups=True) @strawberry_django.filter(models.Device, lookups=True)
@autotype_decorator(filtersets.DeviceFilterSet) class DeviceFilter(
class DeviceFilter(BaseFilterMixin): ContactFilterMixin,
pass TenancyFilterMixin,
ImageAttachmentFilterMixin,
RenderConfigFilterMixin,
ConfigContextFilterMixin,
PrimaryModelFilterMixin,
):
device_type: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
device_type_id: ID | None = strawberry_django.filter_field()
role: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
role_id: ID | None = strawberry_django.filter_field()
platform: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
serial: FilterLookup[str] | None = strawberry_django.filter_field()
asset_tag: FilterLookup[str] | None = strawberry_django.filter_field()
site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
site_id: ID | None = strawberry_django.filter_field()
location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
rack_id: ID | None = strawberry_django.filter_field()
position: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
face: Annotated['DeviceFaceEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
status: Annotated['DeviceStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
airflow: Annotated['DeviceAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
primary_ip4: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip4_id: ID | None = strawberry_django.filter_field()
primary_ip6: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip6_id: ID | None = strawberry_django.filter_field()
oob_ip: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
oob_ip_id: ID | None = strawberry_django.filter_field()
cluster: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
cluster_id: ID | None = strawberry_django.filter_field()
virtual_chassis: Annotated['VirtualChassisFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
virtual_chassis_id: ID | None = strawberry_django.filter_field()
vc_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
vc_priority: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
latitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
longitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
interfaces: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
consoleports: Annotated['ConsolePortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
consoleserverports: Annotated['ConsoleServerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
poweroutlets: Annotated['PowerOutletFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
powerports: Annotated['PowerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
devicebays: Annotated['DeviceBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
frontports: Annotated['FrontPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rearports: Annotated['RearPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
modulebays: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
modules: Annotated['ModuleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
console_port_count: FilterLookup[int] | None = strawberry_django.filter_field()
console_server_port_count: FilterLookup[int] | None = strawberry_django.filter_field()
power_port_count: FilterLookup[int] | None = strawberry_django.filter_field()
power_outlet_count: FilterLookup[int] | None = strawberry_django.filter_field()
interface_count: FilterLookup[int] | None = strawberry_django.filter_field()
front_port_count: FilterLookup[int] | None = strawberry_django.filter_field()
rear_port_count: FilterLookup[int] | None = strawberry_django.filter_field()
device_bay_count: FilterLookup[int] | None = strawberry_django.filter_field()
module_bay_count: FilterLookup[int] | None = strawberry_django.filter_field()
inventory_item_count: FilterLookup[int] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.DeviceBay, lookups=True) @strawberry_django.filter(models.DeviceBay, lookups=True)
@autotype_decorator(filtersets.DeviceBayFilterSet) class DeviceBayFilter(ComponentModelFilterMixin):
class DeviceBayFilter(BaseFilterMixin): installed_device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
installed_device_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.DeviceBayTemplate, lookups=True) @strawberry_django.filter(models.DeviceBayTemplate, lookups=True)
@autotype_decorator(filtersets.DeviceBayTemplateFilterSet) class DeviceBayTemplateFilter(ComponentTemplateFilterMixin):
class DeviceBayTemplateFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.InventoryItemTemplate, lookups=True) @strawberry_django.filter(models.InventoryItemTemplate, lookups=True)
@autotype_decorator(filtersets.InventoryItemTemplateFilterSet) class InventoryItemTemplateFilter(ComponentTemplateFilterMixin):
class InventoryItemTemplateFilter(BaseFilterMixin): parent: Annotated['InventoryItemTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
component_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
component_id: ID | None = strawberry_django.filter_field()
role: Annotated['InventoryItemRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
role_id: ID | None = strawberry_django.filter_field()
manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
part_id: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.DeviceRole, lookups=True) @strawberry_django.filter(models.DeviceRole, lookups=True)
@autotype_decorator(filtersets.DeviceRoleFilterSet) class DeviceRoleFilter(OrganizationalModelFilterMixin, RenderConfigFilterMixin):
class DeviceRoleFilter(BaseFilterMixin): color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
pass vm_role: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.DeviceType, lookups=True) @strawberry_django.filter(models.DeviceType, lookups=True)
@autotype_decorator(filtersets.DeviceTypeFilterSet) class DeviceTypeFilter(ImageAttachmentFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin):
class DeviceTypeFilter(BaseFilterMixin): manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
model: FilterLookup[str] | None = strawberry_django.filter_field()
slug: FilterLookup[str] | None = strawberry_django.filter_field()
default_platform: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
default_platform_id: ID | None = strawberry_django.filter_field()
part_number: FilterLookup[str] | None = strawberry_django.filter_field()
u_height: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
exclude_from_utilization: FilterLookup[bool] | None = strawberry_django.filter_field()
is_full_depth: FilterLookup[bool] | None = strawberry_django.filter_field()
subdevice_role: Annotated['SubdeviceRoleEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
airflow: Annotated['DeviceAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
front_image: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rear_image: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
console_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
console_server_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
power_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
power_outlet_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
interface_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
front_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
rear_port_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
device_bay_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
module_bay_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
inventory_item_template_count: FilterLookup[int] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.FrontPort, lookups=True) @strawberry_django.filter(models.FrontPort, lookups=True)
@autotype_decorator(filtersets.FrontPortFilterSet) class FrontPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class FrontPortFilter(BaseFilterMixin): type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
pass color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
rear_port: Annotated['RearPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rear_port_id: ID | None = strawberry_django.filter_field()
rear_port_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.FrontPortTemplate, lookups=True) @strawberry_django.filter(models.FrontPortTemplate, lookups=True)
@autotype_decorator(filtersets.FrontPortTemplateFilterSet) class FrontPortTemplateFilter(ModularComponentTemplateFilterMixin):
class FrontPortTemplateFilter(BaseFilterMixin): type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
pass color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
rear_port: Annotated['RearPortTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rear_port_id: ID | None = strawberry_django.filter_field()
rear_port_position: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.MACAddress, lookups=True) @strawberry_django.filter(models.MACAddress, lookups=True)
@autotype_decorator(filtersets.MACAddressFilterSet) class MACAddressFilter(PrimaryModelFilterMixin):
class MACAddressFilter(BaseFilterMixin): mac_address: FilterLookup[str] | None = strawberry_django.filter_field()
pass assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
assigned_object_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.Interface, lookups=True) @strawberry_django.filter(models.Interface, lookups=True)
@autotype_decorator(filtersets.InterfaceFilterSet) class InterfaceFilter(ModularComponentModelFilterMixin, InterfaceBaseFilterMixin, CabledObjectModelFilterMixin):
class InterfaceFilter(BaseFilterMixin): vcdcs: Annotated['VirtualDeviceContextFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
lag: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
lag_id: ID | None = strawberry_django.filter_field()
type: Annotated['InterfaceTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
mgmt_only: FilterLookup[bool] | None = strawberry_django.filter_field()
speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
duplex: Annotated['InterfaceDuplexEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
wwn: FilterLookup[str] | None = strawberry_django.filter_field()
rf_role: Annotated['WirelessRoleEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
rf_channel: Annotated['WirelessChannelEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
rf_channel_frequency: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
rf_channel_width: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
tx_power: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
poe_mode: Annotated['InterfacePoEModeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
poe_type: Annotated['InterfacePoETypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
wireless_link: Annotated['WirelessLinkFilter', strawberry.lazy('wireless.graphql.filters')] | None = (
strawberry_django.filter_field()
)
wireless_link_id: ID | None = strawberry_django.filter_field()
wireless_lans: Annotated['WirelessLANFilter', strawberry.lazy('wireless.graphql.filters')] | None = (
strawberry_django.filter_field()
)
vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vrf_id: ID | None = strawberry_django.filter_field()
ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
mac_addresses: Annotated['MACAddressFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
fhrp_group_assignments: Annotated['FHRPGroupAssignmentFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tunnel_terminations: Annotated['TunnelTerminationFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
l2vpn_terminations: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.InterfaceTemplate, lookups=True) @strawberry_django.filter(models.InterfaceTemplate, lookups=True)
@autotype_decorator(filtersets.InterfaceTemplateFilterSet) class InterfaceTemplateFilter(ModularComponentTemplateFilterMixin):
class InterfaceTemplateFilter(BaseFilterMixin): type: Annotated['InterfaceTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
mgmt_only: FilterLookup[bool] | None = strawberry_django.filter_field()
bridge: Annotated['InterfaceTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
bridge_id: ID | None = strawberry_django.filter_field()
poe_mode: Annotated['InterfacePoEModeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
poe_type: Annotated['InterfacePoETypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
rf_role: Annotated['WirelessRoleEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.InventoryItem, lookups=True) @strawberry_django.filter(models.InventoryItem, lookups=True)
@autotype_decorator(filtersets.InventoryItemFilterSet) class InventoryItemFilter(ComponentModelFilterMixin):
class InventoryItemFilter(BaseFilterMixin): parent: Annotated['InventoryItemFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
parent_id: ID | None = strawberry_django.filter_field()
component_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
component_id: ID | None = strawberry_django.filter_field()
status: Annotated['InventoryItemStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
role: Annotated['InventoryItemRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
role_id: ID | None = strawberry_django.filter_field()
manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
part_id: FilterLookup[str] | None = strawberry_django.filter_field()
serial: FilterLookup[str] | None = strawberry_django.filter_field()
asset_tag: FilterLookup[str] | None = strawberry_django.filter_field()
discovered: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.InventoryItemRole, lookups=True) @strawberry_django.filter(models.InventoryItemRole, lookups=True)
@autotype_decorator(filtersets.InventoryItemRoleFilterSet) class InventoryItemRoleFilter(OrganizationalModelFilterMixin):
class InventoryItemRoleFilter(BaseFilterMixin): color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.Location, lookups=True) @strawberry_django.filter(models.Location, lookups=True)
@autotype_decorator(filtersets.LocationFilterSet) class LocationFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, NestedGroupModelFilterMixin):
class LocationFilter(BaseFilterMixin): site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass site_id: ID | None = strawberry_django.filter_field()
status: Annotated['LocationStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
facility: FilterLookup[str] | None = strawberry_django.filter_field()
prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Manufacturer, lookups=True) @strawberry_django.filter(models.Manufacturer, lookups=True)
@autotype_decorator(filtersets.ManufacturerFilterSet) class ManufacturerFilter(ContactFilterMixin, OrganizationalModelFilterMixin):
class ManufacturerFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.Module, lookups=True) @strawberry_django.filter(models.Module, lookups=True)
@autotype_decorator(filtersets.ModuleFilterSet) class ModuleFilter(PrimaryModelFilterMixin, ConfigContextFilterMixin):
class ModuleFilter(BaseFilterMixin): device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass device_id: ID | None = strawberry_django.filter_field()
module_bay: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
module_bay_id: ID | None = strawberry_django.filter_field()
module_type: Annotated['ModuleTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
module_type_id: ID | None = strawberry_django.filter_field()
status: Annotated['ModuleStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
serial: FilterLookup[str] | None = strawberry_django.filter_field()
asset_tag: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ModuleBay, lookups=True) @strawberry_django.filter(models.ModuleBay, lookups=True)
@autotype_decorator(filtersets.ModuleBayFilterSet) class ModuleBayFilter(ModularComponentModelFilterMixin):
class ModuleBayFilter(BaseFilterMixin): parent: Annotated['ModuleBayFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
parent_id: ID | None = strawberry_django.filter_field()
position: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ModuleBayTemplate, lookups=True) @strawberry_django.filter(models.ModuleBayTemplate, lookups=True)
@autotype_decorator(filtersets.ModuleBayTemplateFilterSet) class ModuleBayTemplateFilter(ModularComponentTemplateFilterMixin):
class ModuleBayTemplateFilter(BaseFilterMixin): position: FilterLookup[str] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.ModuleType, lookups=True) @strawberry_django.filter(models.ModuleType, lookups=True)
@autotype_decorator(filtersets.ModuleTypeFilterSet) class ModuleTypeFilter(ImageAttachmentFilterMixin, PrimaryModelFilterMixin, WeightFilterMixin):
class ModuleTypeFilter(BaseFilterMixin): manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
model: FilterLookup[str] | None = strawberry_django.filter_field()
part_number: FilterLookup[str] | None = strawberry_django.filter_field()
airflow: Annotated['ModuleAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Platform, lookups=True) @strawberry_django.filter(models.Platform, lookups=True)
@autotype_decorator(filtersets.PlatformFilterSet) class PlatformFilter(OrganizationalModelFilterMixin):
class PlatformFilter(BaseFilterMixin): manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
config_template: Annotated['ConfigTemplateFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
config_template_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.PowerFeed, lookups=True) @strawberry_django.filter(models.PowerFeed, lookups=True)
@autotype_decorator(filtersets.PowerFeedFilterSet) class PowerFeedFilter(CabledObjectModelFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class PowerFeedFilter(BaseFilterMixin): power_panel: Annotated['PowerPanelFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
power_panel_id: ID | None = strawberry_django.filter_field()
rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
rack_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['PowerFeedStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
type: Annotated['PowerFeedTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
supply: Annotated['PowerFeedSupplyEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
phase: Annotated['PowerFeedPhaseEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
voltage: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
amperage: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
max_utilization: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
available_power: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.PowerOutlet, lookups=True) @strawberry_django.filter(models.PowerOutlet, lookups=True)
@autotype_decorator(filtersets.PowerOutletFilterSet) class PowerOutletFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class PowerOutletFilter(BaseFilterMixin): type: Annotated['PowerOutletTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
power_port: Annotated['PowerPortFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
power_port_id: ID | None = strawberry_django.filter_field()
feed_leg: Annotated['PowerOutletFeedLegEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.PowerOutletTemplate, lookups=True) @strawberry_django.filter(models.PowerOutletTemplate, lookups=True)
@autotype_decorator(filtersets.PowerOutletTemplateFilterSet) class PowerOutletTemplateFilter(ModularComponentModelFilterMixin):
class PowerOutletTemplateFilter(BaseFilterMixin): type: Annotated['PowerOutletTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
power_port: Annotated['PowerPortTemplateFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
power_port_id: ID | None = strawberry_django.filter_field()
feed_leg: Annotated['PowerOutletFeedLegEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.PowerPanel, lookups=True) @strawberry_django.filter(models.PowerPanel, lookups=True)
@autotype_decorator(filtersets.PowerPanelFilterSet) class PowerPanelFilter(ContactFilterMixin, ImageAttachmentFilterMixin, PrimaryModelFilterMixin):
class PowerPanelFilter(BaseFilterMixin): site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass site_id: ID | None = strawberry_django.filter_field()
location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.PowerPort, lookups=True) @strawberry_django.filter(models.PowerPort, lookups=True)
@autotype_decorator(filtersets.PowerPortFilterSet) class PowerPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class PowerPortFilter(BaseFilterMixin): type: Annotated['PowerPortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
maximum_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
allocated_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.PowerPortTemplate, lookups=True) @strawberry_django.filter(models.PowerPortTemplate, lookups=True)
@autotype_decorator(filtersets.PowerPortTemplateFilterSet) class PowerPortTemplateFilter(ModularComponentTemplateFilterMixin):
class PowerPortTemplateFilter(BaseFilterMixin): type: Annotated['PowerPortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
maximum_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
allocated_draw: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.RackType, lookups=True) @strawberry_django.filter(models.RackType, lookups=True)
@autotype_decorator(filtersets.RackTypeFilterSet) class RackTypeFilter(RackBaseFilterMixin):
class RackTypeFilter(BaseFilterMixin): form_factor: Annotated['RackFormFactorEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
manufacturer: Annotated['ManufacturerFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
manufacturer_id: ID | None = strawberry_django.filter_field()
model: FilterLookup[str] | None = strawberry_django.filter_field()
slug: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.Rack, lookups=True) @strawberry_django.filter(models.Rack, lookups=True)
@autotype_decorator(filtersets.RackFilterSet) class RackFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, RackBaseFilterMixin):
class RackFilter(BaseFilterMixin): form_factor: Annotated['RackFormFactorEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
rack_type: Annotated['RackTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rack_type_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
facility_id: FilterLookup[str] | None = strawberry_django.filter_field()
site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
site_id: ID | None = strawberry_django.filter_field()
location: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
location_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
status: Annotated['RackStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
role: Annotated['RackRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
role_id: ID | None = strawberry_django.filter_field()
serial: FilterLookup[str] | None = strawberry_django.filter_field()
asset_tag: FilterLookup[str] | None = strawberry_django.filter_field()
airflow: Annotated['RackAirflowEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.RackReservation, lookups=True) @strawberry_django.filter(models.RackReservation, lookups=True)
@autotype_decorator(filtersets.RackReservationFilterSet) class RackReservationFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class RackReservationFilter(BaseFilterMixin): rack: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass rack_id: ID | None = strawberry_django.filter_field()
units: Annotated['IntegerArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
user_id: ID | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.RackRole, lookups=True) @strawberry_django.filter(models.RackRole, lookups=True)
@autotype_decorator(filtersets.RackRoleFilterSet) class RackRoleFilter(OrganizationalModelFilterMixin):
class RackRoleFilter(BaseFilterMixin): color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.RearPort, lookups=True) @strawberry_django.filter(models.RearPort, lookups=True)
@autotype_decorator(filtersets.RearPortFilterSet) class RearPortFilter(ModularComponentModelFilterMixin, CabledObjectModelFilterMixin):
class RearPortFilter(BaseFilterMixin): type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
pass color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
positions: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.RearPortTemplate, lookups=True) @strawberry_django.filter(models.RearPortTemplate, lookups=True)
@autotype_decorator(filtersets.RearPortTemplateFilterSet) class RearPortTemplateFilter(ModularComponentTemplateFilterMixin):
class RearPortTemplateFilter(BaseFilterMixin): type: Annotated['PortTypeEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
pass color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
positions: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Region, lookups=True) @strawberry_django.filter(models.Region, lookups=True)
@autotype_decorator(filtersets.RegionFilterSet) class RegionFilter(ContactFilterMixin, NestedGroupModelFilterMixin):
class RegionFilter(BaseFilterMixin): prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Site, lookups=True) @strawberry_django.filter(models.Site, lookups=True)
@autotype_decorator(filtersets.SiteFilterSet) class SiteFilter(ContactFilterMixin, ImageAttachmentFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class SiteFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['SiteStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = strawberry_django.filter_field()
region: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
region_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
group: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
facility: FilterLookup[str] | None = strawberry_django.filter_field()
asns: Annotated['ASNFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
time_zone: FilterLookup[str] | None = strawberry_django.filter_field()
physical_address: FilterLookup[str] | None = strawberry_django.filter_field()
shipping_address: FilterLookup[str] | None = strawberry_django.filter_field()
latitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
longitude: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.SiteGroup, lookups=True) @strawberry_django.filter(models.SiteGroup, lookups=True)
@autotype_decorator(filtersets.SiteGroupFilterSet) class SiteGroupFilter(ContactFilterMixin, NestedGroupModelFilterMixin):
class SiteGroupFilter(BaseFilterMixin): prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VirtualChassis, lookups=True) @strawberry_django.filter(models.VirtualChassis, lookups=True)
@autotype_decorator(filtersets.VirtualChassisFilterSet) class VirtualChassisFilter(PrimaryModelFilterMixin):
class VirtualChassisFilter(BaseFilterMixin): master: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass master_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
domain: FilterLookup[str] | None = strawberry_django.filter_field()
member_count: FilterLookup[int] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.VirtualDeviceContext, lookups=True) @strawberry_django.filter(models.VirtualDeviceContext, lookups=True)
@autotype_decorator(filtersets.VirtualDeviceContextFilterSet) class VirtualDeviceContextFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class VirtualDeviceContextFilter(BaseFilterMixin): device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass device_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['VirtualDeviceContextStatusEnum', strawberry.lazy('dcim.graphql.enums')] | None = (
strawberry_django.filter_field()
)
identifier: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
primary_ip4: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip4_id: ID | None = strawberry_django.filter_field()
primary_ip6: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip6_id: ID | None = strawberry_django.filter_field()
comments: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -6,7 +6,11 @@ import strawberry_django
from core.graphql.mixins import ChangelogMixin from core.graphql.mixins import ChangelogMixin
from dcim import models from dcim import models
from extras.graphql.mixins import ( from extras.graphql.mixins import (
ConfigContextMixin, ContactsMixin, CustomFieldsMixin, ImageAttachmentsMixin, TagsMixin, ConfigContextMixin,
ContactsMixin,
CustomFieldsMixin,
ImageAttachmentsMixin,
TagsMixin,
) )
from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin
from netbox.graphql.scalars import BigInt from netbox.graphql.scalars import BigInt
@ -14,6 +18,23 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, Organizationa
from .filters import * from .filters import *
from .mixins import CabledObjectMixin, PathEndpointMixin from .mixins import CabledObjectMixin, PathEndpointMixin
if TYPE_CHECKING:
from circuits.graphql.types import CircuitTerminationType
from extras.graphql.types import ConfigTemplateType
from ipam.graphql.types import (
ASNType,
IPAddressType,
PrefixType,
ServiceType,
VLANTranslationPolicyType,
VLANType,
VRFType,
)
from tenancy.graphql.types import TenantType
from users.graphql.types import UserType
from virtualization.graphql.types import ClusterType, VMInterfaceType, VirtualMachineType
from wireless.graphql.types import WirelessLANType, WirelessLinkType
__all__ = ( __all__ = (
'CableType', 'CableType',
'ComponentType', 'ComponentType',
@ -111,7 +132,7 @@ class ModularComponentTemplateType(ComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.CableTermination, models.CableTermination,
exclude=('termination_type', 'termination_id', '_device', '_rack', '_location', '_site'), exclude=['termination_type', 'termination_id', '_device', '_rack', '_location', '_site'],
filters=CableTerminationFilter filters=CableTerminationFilter
) )
class CableTerminationType(NetBoxObjectType): class CableTerminationType(NetBoxObjectType):
@ -167,7 +188,7 @@ class CableType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.ConsolePort, models.ConsolePort,
exclude=('_path',), exclude=['_path'],
filters=ConsolePortFilter filters=ConsolePortFilter
) )
class ConsolePortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): class ConsolePortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin):
@ -185,7 +206,7 @@ class ConsolePortTemplateType(ModularComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.ConsoleServerPort, models.ConsoleServerPort,
exclude=('_path',), exclude=['_path'],
filters=ConsoleServerPortFilter filters=ConsoleServerPortFilter
) )
class ConsoleServerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): class ConsoleServerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin):
@ -276,7 +297,7 @@ class DeviceBayTemplateType(ComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.InventoryItemTemplate, models.InventoryItemTemplate,
exclude=('component_type', 'component_id', 'parent'), exclude=['component_type', 'component_id', 'parent'],
filters=InventoryItemTemplateFilter filters=InventoryItemTemplateFilter
) )
class InventoryItemTemplateType(ComponentTemplateType): class InventoryItemTemplateType(ComponentTemplateType):
@ -369,7 +390,7 @@ class FrontPortTemplateType(ModularComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.MACAddress, models.MACAddress,
exclude=('assigned_object_type', 'assigned_object_id'), exclude=['assigned_object_type', 'assigned_object_id'],
filters=MACAddressFilter filters=MACAddressFilter
) )
class MACAddressType(NetBoxObjectType): class MACAddressType(NetBoxObjectType):
@ -385,7 +406,7 @@ class MACAddressType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.Interface, models.Interface,
exclude=('_path',), exclude=['_path'],
filters=InterfaceFilter filters=InterfaceFilter
) )
class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin): class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin):
@ -424,7 +445,7 @@ class InterfaceTemplateType(ModularComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.InventoryItem, models.InventoryItem,
exclude=('component_type', 'component_id', 'parent'), exclude=['component_type', 'component_id', 'parent'],
filters=InventoryItemFilter filters=InventoryItemFilter
) )
class InventoryItemType(ComponentType): class InventoryItemType(ComponentType):
@ -463,7 +484,7 @@ class InventoryItemRoleType(OrganizationalObjectType):
@strawberry_django.type( @strawberry_django.type(
models.Location, models.Location,
# fields='__all__', # fields='__all__',
exclude=('parent',), # bug - temp exclude=['parent'], # bug - temp
filters=LocationFilter filters=LocationFilter
) )
class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, OrganizationalObjectType): class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, OrganizationalObjectType):
@ -524,7 +545,7 @@ class ModuleType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.ModuleBay, models.ModuleBay,
# fields='__all__', # fields='__all__',
exclude=('parent',), exclude=['parent'],
filters=ModuleBayFilter filters=ModuleBayFilter
) )
class ModuleBayType(ModularComponentType): class ModuleBayType(ModularComponentType):
@ -579,7 +600,7 @@ class PlatformType(OrganizationalObjectType):
@strawberry_django.type( @strawberry_django.type(
models.PowerFeed, models.PowerFeed,
exclude=('_path',), exclude=['_path'],
filters=PowerFeedFilter filters=PowerFeedFilter
) )
class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin): class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin):
@ -590,7 +611,7 @@ class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin):
@strawberry_django.type( @strawberry_django.type(
models.PowerOutlet, models.PowerOutlet,
exclude=('_path',), exclude=['_path'],
filters=PowerOutletFilter filters=PowerOutletFilter
) )
class PowerOutletType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): class PowerOutletType(ModularComponentType, CabledObjectMixin, PathEndpointMixin):
@ -621,7 +642,7 @@ class PowerPanelType(NetBoxObjectType, ContactsMixin):
@strawberry_django.type( @strawberry_django.type(
models.PowerPort, models.PowerPort,
exclude=('_path',), exclude=['_path'],
filters=PowerPortFilter filters=PowerPortFilter
) )
class PowerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin): class PowerPortType(ModularComponentType, CabledObjectMixin, PathEndpointMixin):
@ -712,8 +733,7 @@ class RearPortTemplateType(ModularComponentTemplateType):
@strawberry_django.type( @strawberry_django.type(
models.Region, models.Region,
exclude=('parent',), exclude=['parent'],
# fields='__all__',
filters=RegionFilter filters=RegionFilter
) )
class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):
@ -772,8 +792,7 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje
@strawberry_django.type( @strawberry_django.type(
models.SiteGroup, models.SiteGroup,
# fields='__all__', exclude=['parent'], # bug - temp
exclude=('parent',), # bug - temp
filters=SiteGroupFilter filters=SiteGroupFilter
) )
class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):

View File

@ -0,0 +1,26 @@
import strawberry
from extras.choices import *
__all__ = (
'CustomFieldChoiceSetBaseEnum',
'CustomFieldFilterLogicEnum',
'CustomFieldTypeEnum',
'CustomFieldUIEditableEnum',
'CustomFieldUIVisibleEnum',
'CustomLinkButtonClassEnum',
'EventRuleActionEnum',
'JournalEntryKindEnum',
'WebhookHttpMethodEnum',
)
CustomFieldChoiceSetBaseEnum = strawberry.enum(CustomFieldChoiceSetBaseChoices.as_enum())
CustomFieldFilterLogicEnum = strawberry.enum(CustomFieldFilterLogicChoices.as_enum())
CustomFieldTypeEnum = strawberry.enum(CustomFieldTypeChoices.as_enum())
CustomFieldUIEditableEnum = strawberry.enum(CustomFieldUIEditableChoices.as_enum())
CustomFieldUIVisibleEnum = strawberry.enum(CustomFieldUIVisibleChoices.as_enum())
CustomLinkButtonClassEnum = strawberry.enum(CustomLinkButtonClassChoices.as_enum())
EventRuleActionEnum = strawberry.enum(EventRuleActionChoices.as_enum())
JournalEntryKindEnum = strawberry.enum(JournalEntryKindChoices.as_enum())
WebhookHttpMethodEnum = strawberry.enum(WebhookHttpMethodChoices.as_enum())

View File

@ -0,0 +1,52 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import BaseFilterMixin
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import JSONFilter
from .filters import *
__all__ = (
'CustomFieldsFilterMixin',
'JournalEntriesFilterMixin',
'TagsFilterMixin',
'ConfigContextFilterMixin',
'TagBaseFilterMixin',
)
@dataclass
class CustomFieldsFilterMixin(BaseFilterMixin):
custom_field_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@dataclass
class JournalEntriesFilterMixin(BaseFilterMixin):
journal_entries: Annotated['JournalEntryFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@dataclass
class TagsFilterMixin(BaseFilterMixin):
tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field()
@dataclass
class ConfigContextFilterMixin(BaseFilterMixin):
local_context_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@dataclass
class TagBaseFilterMixin(BaseFilterMixin):
name: FilterLookup[str] | None = strawberry_django.filter_field()
slug: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,7 +1,26 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from extras import filtersets, models import strawberry
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin
from extras import models
from extras.graphql.filter_mixins import TagBaseFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin
from netbox.graphql.filter_mixins import SyncedDataFilterMixin
if TYPE_CHECKING:
from core.graphql.filters import ContentTypeFilter
from dcim.graphql.filters import (
DeviceRoleFilter, DeviceTypeFilter, LocationFilter, PlatformFilter, RegionFilter, SiteFilter, SiteGroupFilter,
)
from tenancy.graphql.filters import TenantFilter, TenantGroupFilter
from netbox.graphql.enums import ColorEnum
from netbox.graphql.filter_lookups import IntegerLookup, JSONFilter, StringArrayLookup, TreeNodeFilter
from users.graphql.filters import GroupFilter, UserFilter
from virtualization.graphql.filters import ClusterFilter, ClusterGroupFilter, ClusterTypeFilter
from .enums import *
__all__ = ( __all__ = (
'ConfigContextFilter', 'ConfigContextFilter',
@ -21,78 +40,263 @@ __all__ = (
@strawberry_django.filter(models.ConfigContext, lookups=True) @strawberry_django.filter(models.ConfigContext, lookups=True)
@autotype_decorator(filtersets.ConfigContextFilterSet) class ConfigContextFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin):
class ConfigContextFilter(BaseFilterMixin): name: FilterLookup[str] = strawberry_django.filter_field()
pass weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
description: FilterLookup[str] = strawberry_django.filter_field()
is_active: FilterLookup[bool] = strawberry_django.filter_field()
regions: Annotated['RegionFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
region_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
site_groups: Annotated['SiteGroupFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
site_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
sites: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
locations: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
device_types: Annotated['DeviceTypeFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
roles: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
platforms: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
cluster_types: Annotated['ClusterTypeFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
cluster_groups: Annotated['ClusterGroupFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
clusters: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tenant_groups: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tenant_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
tenants: Annotated['TenantFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tags: Annotated['TagFilter', strawberry.lazy('extras.graphql.filters')] | None = strawberry_django.filter_field()
data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ConfigTemplate, lookups=True) @strawberry_django.filter(models.ConfigTemplate, lookups=True)
@autotype_decorator(filtersets.ConfigTemplateFilterSet) class ConfigTemplateFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin):
class ConfigTemplateFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
template_code: FilterLookup[str] | None = strawberry_django.filter_field()
environment_params: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.CustomField, lookups=True) @strawberry_django.filter(models.CustomField, lookups=True)
@autotype_decorator(filtersets.CustomFieldFilterSet) class CustomFieldFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class CustomFieldFilter(BaseFilterMixin): type: Annotated['CustomFieldTypeEnum', strawberry.lazy('extras.graphql.enums')] | None = (
pass strawberry_django.filter_field()
)
object_types: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
related_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
label: FilterLookup[str] | None = strawberry_django.filter_field()
group_name: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
required: FilterLookup[bool] | None = strawberry_django.filter_field()
unique: FilterLookup[bool] | None = strawberry_django.filter_field()
search_weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
filter_logic: Annotated['CustomFieldFilterLogicEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
default: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
related_object_filter: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
validation_minimum: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
validation_maximum: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
validation_regex: FilterLookup[str] | None = strawberry_django.filter_field()
choice_set: Annotated['CustomFieldChoiceSetFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
choice_set_id: ID | None = strawberry_django.filter_field()
ui_visible: Annotated['CustomFieldUIVisibleEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
ui_editable: Annotated['CustomFieldUIEditableEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
is_cloneable: FilterLookup[bool] | None = strawberry_django.filter_field()
comments: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.CustomFieldChoiceSet, lookups=True) @strawberry_django.filter(models.CustomFieldChoiceSet, lookups=True)
@autotype_decorator(filtersets.CustomFieldChoiceSetFilterSet) class CustomFieldChoiceSetFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class CustomFieldChoiceSetFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
base_choices: Annotated['CustomFieldChoiceSetBaseEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
extra_choices: Annotated['StringArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
order_alphabetically: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.CustomLink, lookups=True) @strawberry_django.filter(models.CustomLink, lookups=True)
@autotype_decorator(filtersets.CustomLinkFilterSet) class CustomLinkFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class CustomLinkFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
link_text: FilterLookup[str] | None = strawberry_django.filter_field()
link_url: FilterLookup[str] | None = strawberry_django.filter_field()
weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
group_name: FilterLookup[str] | None = strawberry_django.filter_field()
button_class: Annotated['CustomLinkButtonClassEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
new_window: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ExportTemplate, lookups=True) @strawberry_django.filter(models.ExportTemplate, lookups=True)
@autotype_decorator(filtersets.ExportTemplateFilterSet) class ExportTemplateFilter(BaseObjectTypeFilterMixin, SyncedDataFilterMixin, ChangeLogFilterMixin):
class ExportTemplateFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
template_code: FilterLookup[str] | None = strawberry_django.filter_field()
mime_type: FilterLookup[str] | None = strawberry_django.filter_field()
file_extension: FilterLookup[str] | None = strawberry_django.filter_field()
as_attachment: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.ImageAttachment, lookups=True) @strawberry_django.filter(models.ImageAttachment, lookups=True)
@autotype_decorator(filtersets.ImageAttachmentFilterSet) class ImageAttachmentFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class ImageAttachmentFilter(BaseFilterMixin): object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
object_id: ID | None = strawberry_django.filter_field()
image_height: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
image_width: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.JournalEntry, lookups=True) @strawberry_django.filter(models.JournalEntry, lookups=True)
@autotype_decorator(filtersets.JournalEntryFilterSet) class JournalEntryFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin):
class JournalEntryFilter(BaseFilterMixin): assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
assigned_object_type_id: ID | None = strawberry_django.filter_field()
assigned_object_id: ID | None = strawberry_django.filter_field()
created_by: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = (
strawberry_django.filter_field()
)
kind: Annotated['JournalEntryKindEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
comments: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.NotificationGroup, lookups=True) @strawberry_django.filter(models.NotificationGroup, lookups=True)
@autotype_decorator(filtersets.NotificationGroupFilterSet) class NotificationGroupFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class NotificationGroupFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
users: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.SavedFilter, lookups=True) @strawberry_django.filter(models.SavedFilter, lookups=True)
@autotype_decorator(filtersets.SavedFilterFilterSet) class SavedFilterFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class SavedFilterFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
user: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
user_id: ID | None = strawberry_django.filter_field()
weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
shared: FilterLookup[bool] | None = strawberry_django.filter_field()
parameters: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Tag, lookups=True) @strawberry_django.filter(models.Tag, lookups=True)
@autotype_decorator(filtersets.TagFilterSet) class TagFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin, TagBaseFilterMixin):
class TagFilter(BaseFilterMixin): color: Annotated['ColorEnum', strawberry.lazy('netbox.graphql.enums')] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.Webhook, lookups=True) @strawberry_django.filter(models.Webhook, lookups=True)
@autotype_decorator(filtersets.WebhookFilterSet) class WebhookFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin):
class WebhookFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
payload_url: FilterLookup[str] | None = strawberry_django.filter_field()
http_method: Annotated['WebhookHttpMethodEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
http_content_type: FilterLookup[str] | None = strawberry_django.filter_field()
additional_headers: FilterLookup[str] | None = strawberry_django.filter_field()
body_template: FilterLookup[str] | None = strawberry_django.filter_field()
secret: FilterLookup[str] | None = strawberry_django.filter_field()
ssl_verification: FilterLookup[bool] | None = strawberry_django.filter_field()
ca_file_path: FilterLookup[str] | None = strawberry_django.filter_field()
events: Annotated['EventRuleFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.EventRule, lookups=True) @strawberry_django.filter(models.EventRule, lookups=True)
@autotype_decorator(filtersets.EventRuleFilterSet) class EventRuleFilter(BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin):
class EventRuleFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
event_types: Annotated['StringArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
conditions: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
action_type: Annotated['EventRuleActionEnum', strawberry.lazy('extras.graphql.enums')] | None = (
strawberry_django.filter_field()
)
action_object_type: FilterLookup[str] | None = strawberry_django.filter_field()
action_object_type_id: ID | None = strawberry_django.filter_field()
action_object_id: ID | None = strawberry_django.filter_field()
action_data: Annotated['JSONFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
comments: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,4 +1,4 @@
from typing import Annotated, List from typing import Annotated, List, TYPE_CHECKING
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -8,6 +8,22 @@ from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
from netbox.graphql.types import BaseObjectType, ContentTypeType, ObjectType, OrganizationalObjectType from netbox.graphql.types import BaseObjectType, ContentTypeType, ObjectType, OrganizationalObjectType
from .filters import * from .filters import *
if TYPE_CHECKING:
from core.graphql.types import DataFileType, DataSourceType
from dcim.graphql.types import (
DeviceRoleType,
DeviceType,
DeviceTypeType,
LocationType,
PlatformType,
RegionType,
SiteGroupType,
SiteType,
)
from tenancy.graphql.types import TenantGroupType, TenantType
from users.graphql.types import GroupType, UserType
from virtualization.graphql.types import ClusterGroupType, ClusterType, ClusterTypeType, VirtualMachineType
__all__ = ( __all__ = (
'ConfigContextType', 'ConfigContextType',
'ConfigTemplateType', 'ConfigTemplateType',
@ -35,7 +51,6 @@ __all__ = (
class ConfigContextType(ObjectType): class ConfigContextType(ObjectType):
data_source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] | None data_source: Annotated["DataSourceType", strawberry.lazy('core.graphql.types')] | None
data_file: Annotated["DataFileType", strawberry.lazy('core.graphql.types')] | None data_file: Annotated["DataFileType", strawberry.lazy('core.graphql.types')] | None
roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]] roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]]
device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]] device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]]
tags: List[Annotated["TagType", strawberry.lazy('extras.graphql.types')]] tags: List[Annotated["TagType", strawberry.lazy('extras.graphql.types')]]
@ -78,7 +93,7 @@ class CustomFieldType(ObjectType):
@strawberry_django.type( @strawberry_django.type(
models.CustomFieldChoiceSet, models.CustomFieldChoiceSet,
exclude=('extra_choices', ), exclude=['extra_choices'],
filters=CustomFieldChoiceSetFilter filters=CustomFieldChoiceSetFilter
) )
class CustomFieldChoiceSetType(ObjectType): class CustomFieldChoiceSetType(ObjectType):

View File

@ -0,0 +1,27 @@
import strawberry
from ipam.choices import *
__all__ = (
'FHRPGroupAuthTypeEnum',
'FHRPGroupProtocolEnum',
'IPAddressFamilyEnum',
'IPAddressRoleEnum',
'IPAddressStatusEnum',
'IPRangeStatusEnum',
'PrefixStatusEnum',
'ServiceProtocolEnum',
'VLANStatusEnum',
'VLANQinQRoleEnum',
)
FHRPGroupAuthTypeEnum = strawberry.enum(FHRPGroupAuthTypeChoices.as_enum())
FHRPGroupProtocolEnum = strawberry.enum(FHRPGroupProtocolChoices.as_enum())
IPAddressFamilyEnum = strawberry.enum(IPAddressFamilyChoices.as_enum())
IPAddressRoleEnum = strawberry.enum(IPAddressRoleChoices.as_enum())
IPAddressStatusEnum = strawberry.enum(IPAddressStatusChoices.as_enum())
IPRangeStatusEnum = strawberry.enum(IPRangeStatusChoices.as_enum())
PrefixStatusEnum = strawberry.enum(PrefixStatusChoices.as_enum())
ServiceProtocolEnum = strawberry.enum(ServiceProtocolChoices.as_enum())
VLANStatusEnum = strawberry.enum(VLANStatusChoices.as_enum())
VLANQinQRoleEnum = strawberry.enum(VLANQinQRoleChoices.as_enum())

View File

@ -0,0 +1,25 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from core.graphql.filter_mixins import BaseFilterMixin
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import IntegerLookup
from .enums import *
__all__ = (
'ServiceBaseFilterMixin',
)
@dataclass
class ServiceBaseFilterMixin(BaseFilterMixin):
protocol: Annotated['ServiceProtocolEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
ports: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,7 +1,28 @@
import strawberry_django from datetime import date
from typing import Annotated, TYPE_CHECKING
from ipam import filtersets, models import netaddr
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
import strawberry_django
from django.db.models import Q
from netaddr.core import AddrFormatError
from strawberry.scalars import ID
from strawberry_django import FilterLookup, DateFilterLookup
from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin
from dcim.graphql.filter_mixins import ScopedFilterMixin
from ipam import models
from ipam.graphql.filter_mixins import ServiceBaseFilterMixin
from netbox.graphql.filter_mixins import NetBoxModelFilterMixin, OrganizationalModelFilterMixin, PrimaryModelFilterMixin
from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import IntegerArrayLookup, IntegerLookup
from core.graphql.filters import ContentTypeFilter
from dcim.graphql.filters import DeviceFilter, SiteFilter
from virtualization.graphql.filters import VirtualMachineFilter
from vpn.graphql.filters import L2VPNFilter
from .enums import *
__all__ = ( __all__ = (
'ASNFilter', 'ASNFilter',
@ -26,108 +47,258 @@ __all__ = (
@strawberry_django.filter(models.ASN, lookups=True) @strawberry_django.filter(models.ASN, lookups=True)
@autotype_decorator(filtersets.ASNFilterSet) class ASNFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class ASNFilter(BaseFilterMixin): rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
pass rir_id: ID | None = strawberry_django.filter_field()
asn: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ASNRange, lookups=True) @strawberry_django.filter(models.ASNRange, lookups=True)
@autotype_decorator(filtersets.ASNRangeFilterSet) class ASNRangeFilter(TenancyFilterMixin, OrganizationalModelFilterMixin):
class ASNRangeFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
rir_id: ID | None = strawberry_django.filter_field()
start: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
end: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Aggregate, lookups=True) @strawberry_django.filter(models.Aggregate, lookups=True)
@autotype_decorator(filtersets.AggregateFilterSet) class AggregateFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class AggregateFilter(BaseFilterMixin): prefix: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
pass prefix_id: ID | None = strawberry_django.filter_field()
rir: Annotated['RIRFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
rir_id: ID | None = strawberry_django.filter_field()
date_added: DateFilterLookup[date] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.FHRPGroup, lookups=True) @strawberry_django.filter(models.FHRPGroup, lookups=True)
@autotype_decorator(filtersets.FHRPGroupFilterSet) class FHRPGroupFilter(PrimaryModelFilterMixin):
class FHRPGroupFilter(BaseFilterMixin): group_id: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
pass strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
protocol: Annotated['FHRPGroupProtocolEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
auth_type: Annotated['FHRPGroupAuthTypeEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
auth_key: FilterLookup[str] | None = strawberry_django.filter_field()
ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.FHRPGroupAssignment, lookups=True) @strawberry_django.filter(models.FHRPGroupAssignment, lookups=True)
@autotype_decorator(filtersets.FHRPGroupAssignmentFilterSet) class FHRPGroupAssignmentFilter(BaseObjectTypeFilterMixin, ChangeLogFilterMixin):
class FHRPGroupAssignmentFilter(BaseFilterMixin): interface_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
interface_id: FilterLookup[str] | None = strawberry_django.filter_field()
group: Annotated['FHRPGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
priority: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.IPAddress, lookups=True) @strawberry_django.filter(models.IPAddress, lookups=True)
@autotype_decorator(filtersets.IPAddressFilterSet) class IPAddressFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class IPAddressFilter(BaseFilterMixin): address: FilterLookup[str] | None = strawberry_django.filter_field()
pass vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vrf_id: ID | None = strawberry_django.filter_field()
status: Annotated['IPAddressStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
role: Annotated['IPAddressRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
assigned_object_id: ID | None = strawberry_django.filter_field()
nat_inside: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
nat_inside_id: ID | None = strawberry_django.filter_field()
nat_outside: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
nat_outside_id: ID | None = strawberry_django.filter_field()
dns_name: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter_field()
def parent(self, value: list[str], prefix) -> Q:
if not value:
return Q()
q = Q()
for subnet in value:
try:
query = str(netaddr.IPNetwork(subnet.strip()).cidr)
q |= Q(address__net_host_contained=query)
except (AddrFormatError, ValueError):
return Q()
return q
@strawberry_django.filter(models.IPRange, lookups=True) @strawberry_django.filter(models.IPRange, lookups=True)
@autotype_decorator(filtersets.IPRangeFilterSet) class IPRangeFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class IPRangeFilter(BaseFilterMixin): start_address: FilterLookup[str] | None = strawberry_django.filter_field()
pass end_address: FilterLookup[str] | None = strawberry_django.filter_field()
size: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vrf_id: ID | None = strawberry_django.filter_field()
status: Annotated['IPRangeStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
role: Annotated['IPAddressRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
mark_utilized: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter_field()
def parent(self, value: list[str], prefix) -> Q:
if not value:
return Q()
q = Q()
for subnet in value:
try:
query = str(netaddr.IPNetwork(subnet.strip()).cidr)
q |= Q(start_address__net_host_contained=query, end_address__net_host_contained=query)
except (AddrFormatError, ValueError):
return Q()
return q
@strawberry_django.filter(models.Prefix, lookups=True) @strawberry_django.filter(models.Prefix, lookups=True)
@autotype_decorator(filtersets.PrefixFilterSet) class PrefixFilter(ContactFilterMixin, ScopedFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class PrefixFilter(BaseFilterMixin): prefix: FilterLookup[str] | None = strawberry_django.filter_field()
pass vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vrf_id: ID | None = strawberry_django.filter_field()
vlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vlan_id: ID | None = strawberry_django.filter_field()
status: Annotated['PrefixStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
role: Annotated['RoleFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
role_id: ID | None = strawberry_django.filter_field()
is_pool: FilterLookup[bool] | None = strawberry_django.filter_field()
mark_utilized: FilterLookup[bool] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.RIR, lookups=True) @strawberry_django.filter(models.RIR, lookups=True)
@autotype_decorator(filtersets.RIRFilterSet) class RIRFilter(OrganizationalModelFilterMixin):
class RIRFilter(BaseFilterMixin): is_private: FilterLookup[bool] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.Role, lookups=True) @strawberry_django.filter(models.Role, lookups=True)
@autotype_decorator(filtersets.RoleFilterSet) class RoleFilter(OrganizationalModelFilterMixin):
class RoleFilter(BaseFilterMixin): weight: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.RouteTarget, lookups=True) @strawberry_django.filter(models.RouteTarget, lookups=True)
@autotype_decorator(filtersets.RouteTargetFilterSet) class RouteTargetFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class RouteTargetFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.Service, lookups=True) @strawberry_django.filter(models.Service, lookups=True)
@autotype_decorator(filtersets.ServiceFilterSet) class ServiceFilter(ContactFilterMixin, ServiceBaseFilterMixin, PrimaryModelFilterMixin):
class ServiceFilter(BaseFilterMixin): device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass device_id: ID | None = strawberry_django.filter_field()
virtual_machine: Annotated['VirtualMachineFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
virtual_machine_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
ipaddresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ServiceTemplate, lookups=True) @strawberry_django.filter(models.ServiceTemplate, lookups=True)
@autotype_decorator(filtersets.ServiceTemplateFilterSet) class ServiceTemplateFilter(ServiceBaseFilterMixin, PrimaryModelFilterMixin):
class ServiceTemplateFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.VLAN, lookups=True) @strawberry_django.filter(models.VLAN, lookups=True)
@autotype_decorator(filtersets.VLANFilterSet) class VLANFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class VLANFilter(BaseFilterMixin): site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
pass site_id: ID | None = strawberry_django.filter_field()
group: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
name: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['VLANStatusEnum', strawberry.lazy('ipam.graphql.enums')] | None = strawberry_django.filter_field()
role: Annotated['RoleFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
role_id: ID | None = strawberry_django.filter_field()
qinq_svlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
qinq_svlan_id: ID | None = strawberry_django.filter_field()
qinq_cvlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
qinq_cvlan_id: ID | None = strawberry_django.filter_field()
qinq_role: Annotated['VLANQinQRoleEnum', strawberry.lazy('ipam.graphql.enums')] | None = (
strawberry_django.filter_field()
)
l2vpn_terminations: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VLANGroup, lookups=True) @strawberry_django.filter(models.VLANGroup, lookups=True)
@autotype_decorator(filtersets.VLANGroupFilterSet) class VLANGroupFilter(ScopedFilterMixin, OrganizationalModelFilterMixin):
class VLANGroupFilter(BaseFilterMixin): vid_ranges: Annotated['IntegerArrayLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.VLANTranslationPolicy, lookups=True) @strawberry_django.filter(models.VLANTranslationPolicy, lookups=True)
@autotype_decorator(filtersets.VLANTranslationPolicyFilterSet) class VLANTranslationPolicyFilter(PrimaryModelFilterMixin):
class VLANTranslationPolicyFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass
@strawberry_django.filter(models.VLANTranslationRule, lookups=True) @strawberry_django.filter(models.VLANTranslationRule, lookups=True)
@autotype_decorator(filtersets.VLANTranslationRuleFilterSet) class VLANTranslationRuleFilter(NetBoxModelFilterMixin):
class VLANTranslationRuleFilter(BaseFilterMixin): policy: Annotated['VLANTranslationPolicyFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
policy_id: ID | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
local_vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
remote_vid: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VRF, lookups=True) @strawberry_django.filter(models.VRF, lookups=True)
@autotype_decorator(filtersets.VRFFilterSet) class VRFFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class VRFFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass rd: FilterLookup[str] | None = strawberry_django.filter_field()
enforce_unique: FilterLookup[bool] | None = strawberry_django.filter_field()
import_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
export_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -11,6 +11,21 @@ from netbox.graphql.types import BaseObjectType, NetBoxObjectType, Organizationa
from .filters import * from .filters import *
from .mixins import IPAddressesMixin from .mixins import IPAddressesMixin
if TYPE_CHECKING:
from dcim.graphql.types import (
DeviceType,
InterfaceType,
LocationType,
RackType,
RegionType,
SiteGroupType,
SiteType,
)
from tenancy.graphql.types import TenantType
from virtualization.graphql.types import ClusterGroupType, ClusterType, VMInterfaceType, VirtualMachineType
from vpn.graphql.types import L2VPNType, TunnelTerminationType
from wireless.graphql.types import WirelessLANType
__all__ = ( __all__ = (
'ASNType', 'ASNType',
'ASNRangeType', 'ASNRangeType',
@ -101,7 +116,7 @@ class FHRPGroupType(NetBoxObjectType, IPAddressesMixin):
@strawberry_django.type( @strawberry_django.type(
models.FHRPGroupAssignment, models.FHRPGroupAssignment,
exclude=('interface_type', 'interface_id'), exclude=['interface_type', 'interface_id'],
filters=FHRPGroupAssignmentFilter filters=FHRPGroupAssignmentFilter
) )
class FHRPGroupAssignmentType(BaseObjectType): class FHRPGroupAssignmentType(BaseObjectType):
@ -117,7 +132,7 @@ class FHRPGroupAssignmentType(BaseObjectType):
@strawberry_django.type( @strawberry_django.type(
models.IPAddress, models.IPAddress,
exclude=('assigned_object_type', 'assigned_object_id', 'address'), exclude=['assigned_object_type', 'assigned_object_id', 'address'],
filters=IPAddressFilter filters=IPAddressFilter
) )
class IPAddressType(NetBoxObjectType, BaseIPAddressFamilyType): class IPAddressType(NetBoxObjectType, BaseIPAddressFamilyType):
@ -154,7 +169,7 @@ class IPRangeType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.Prefix, models.Prefix,
exclude=('scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'), exclude=['scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'],
filters=PrefixFilter filters=PrefixFilter
) )
class PrefixType(NetBoxObjectType, BaseIPAddressFamilyType): class PrefixType(NetBoxObjectType, BaseIPAddressFamilyType):
@ -236,7 +251,7 @@ class ServiceTemplateType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.VLAN, models.VLAN,
exclude=('qinq_svlan',), exclude=['qinq_svlan'],
filters=VLANFilter filters=VLANFilter
) )
class VLANType(NetBoxObjectType): class VLANType(NetBoxObjectType):
@ -259,7 +274,7 @@ class VLANType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.VLANGroup, models.VLANGroup,
exclude=('scope_type', 'scope_id'), exclude=['scope_type', 'scope_id'],
filters=VLANGroupFilter filters=VLANGroupFilter
) )
class VLANGroupType(OrganizationalObjectType): class VLANGroupType(OrganizationalObjectType):

View File

@ -0,0 +1,13 @@
import strawberry
from netbox.choices import *
__all__ = (
'ColorEnum',
'DistanceUnitEnum',
'WeightUnitEnum',
)
ColorEnum = strawberry.enum(ColorChoices.as_enum())
DistanceUnitEnum = strawberry.enum(DistanceUnitChoices.as_enum())
WeightUnitEnum = strawberry.enum(WeightUnitChoices.as_enum())

View File

@ -0,0 +1,219 @@
from enum import Enum
from typing import TypeVar, Tuple, Generic
import strawberry
import strawberry_django
from django.core.exceptions import FieldDoesNotExist
from django.db.models import Q, QuerySet
from django.db.models.fields.related import ForeignKey, ManyToManyField, ManyToManyRel, ManyToOneRel
from strawberry import ID
from strawberry.types import Info
from strawberry_django import (
ComparisonFilterLookup,
DateFilterLookup,
DatetimeFilterLookup,
FilterLookup,
RangeLookup,
TimeFilterLookup,
process_filters,
)
__all__ = (
'ArrayLookup',
'FloatArrayLookup',
'FloatLookup',
'IntegerArrayLookup',
'IntegerLookup',
'JSONFilter',
'StringArrayLookup',
'TreeNodeFilter',
)
T = TypeVar('T')
SKIP_MSG = 'Filter will be skipped on `null` value'
@strawberry.input(one_of=True, description='Lookup for JSON field. Only one of the lookup fields can be set.')
class JSONLookup:
string_lookup: FilterLookup[str] | None = strawberry_django.filter_field()
int_range_lookup: RangeLookup[int] | None = strawberry_django.filter_field()
int_comparison_lookup: ComparisonFilterLookup[int] | None = strawberry_django.filter_field()
float_range_lookup: RangeLookup[float] | None = strawberry_django.filter_field()
float_comparison_lookup: ComparisonFilterLookup[float] | None = strawberry_django.filter_field()
date_lookup: DateFilterLookup[str] | None = strawberry_django.filter_field()
datetime_lookup: DatetimeFilterLookup[str] | None = strawberry_django.filter_field()
time_lookup: TimeFilterLookup[str] | None = strawberry_django.filter_field()
boolean_lookup: FilterLookup[bool] | None = strawberry_django.filter_field()
def get_filter(self):
for field in self.__strawberry_definition__.fields:
value = getattr(self, field.name, None)
if value is not strawberry.UNSET:
return value
return None
@strawberry.input(one_of=True, description='Lookup for Integer fields. Only one of the lookup fields can be set.')
class IntegerLookup:
filter_lookup: FilterLookup[int] | None = strawberry_django.filter_field()
range_lookup: RangeLookup[int] | None = strawberry_django.filter_field()
comparison_lookup: ComparisonFilterLookup[int] | None = strawberry_django.filter_field()
def get_filter(self):
for field in self.__strawberry_definition__.fields:
value = getattr(self, field.name, None)
if value is not strawberry.UNSET:
return value
return None
@strawberry_django.filter_field
def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]:
filters = self.get_filter()
if not filters:
return queryset, Q()
return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix)
@strawberry.input(one_of=True, description='Lookup for Float fields. Only one of the lookup fields can be set.')
class FloatLookup:
filter_lookup: FilterLookup[float] | None = strawberry_django.filter_field()
range_lookup: RangeLookup[float] | None = strawberry_django.filter_field()
comparison_lookup: ComparisonFilterLookup[float] | None = strawberry_django.filter_field()
def get_filter(self):
for field in self.__strawberry_definition__.fields:
value = getattr(self, field.name, None)
if value is not strawberry.UNSET:
return value
return None
@strawberry_django.filter_field
def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]:
filters = self.get_filter()
if not filters:
return queryset, Q()
return process_filters(filters=filters, queryset=queryset, info=info, prefix=prefix)
@strawberry.input
class JSONFilter:
"""
Class for JSON field lookups with paths
"""
path: str
lookup: JSONLookup
@strawberry_django.filter_field
def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]:
filters = self.lookup.get_filter()
if not filters:
return queryset, Q()
json_path = f'{prefix}{self.path}__'
return process_filters(filters=filters, queryset=queryset, info=info, prefix=json_path)
@strawberry.enum
class TreeNodeMatch(Enum):
EXACT = 'exact' # Just the node itself
DESCENDANTS = 'descendants' # Node and all descendants
SELF_AND_DESCENDANTS = 'self_and_descendants' # Node and all descendants
CHILDREN = 'children' # Just immediate children
SIBLINGS = 'siblings' # Nodes with same parent
ANCESTORS = 'ancestors' # All parent nodes
PARENT = 'parent' # Just immediate parent
@strawberry.input
class TreeNodeFilter:
id: ID
match_type: TreeNodeMatch
@strawberry_django.filter_field
def filter(self, info: Info, queryset: QuerySet, prefix: str = '') -> Tuple[QuerySet, Q]:
model_field_name = prefix.removesuffix('__').removesuffix('_id')
model_field = None
try:
model_field = queryset.model._meta.get_field(model_field_name)
except FieldDoesNotExist:
try:
model_field = queryset.model._meta.get_field(f'{model_field_name}s')
except FieldDoesNotExist:
return queryset, Q(pk__in=[])
if hasattr(model_field, 'related_model'):
related_model = model_field.related_model
else:
return queryset, Q(pk__in=[])
# Generate base Q filter for the related model without prefix
q_filter = generate_tree_node_q_filter(related_model, self)
# Handle different relationship types
if isinstance(model_field, (ManyToManyField, ManyToManyRel)):
return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)})
elif isinstance(model_field, ForeignKey):
return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children})
elif isinstance(model_field, ManyToOneRel):
return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)})
else:
return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children})
def generate_tree_node_q_filter(model_class, filter_value: TreeNodeFilter) -> Q:
"""
Generate appropriate Q filter for MPTT tree filtering based on match type
"""
try:
node = model_class.objects.get(id=filter_value.id)
except model_class.DoesNotExist:
return Q(pk__in=[])
if filter_value.match_type == TreeNodeMatch.EXACT:
return Q(id=filter_value.id)
elif filter_value.match_type == TreeNodeMatch.DESCENDANTS:
return Q(tree_id=node.tree_id, lft__gt=node.lft, rght__lt=node.rght)
elif filter_value.match_type == TreeNodeMatch.SELF_AND_DESCENDANTS:
return Q(tree_id=node.tree_id, lft__gte=node.lft, rght__lte=node.rght)
elif filter_value.match_type == TreeNodeMatch.CHILDREN:
return Q(tree_id=node.tree_id, level=node.level + 1, lft__gt=node.lft, rght__lt=node.rght)
elif filter_value.match_type == TreeNodeMatch.SIBLINGS:
return Q(tree_id=node.tree_id, level=node.level, parent=node.parent) & ~Q(id=node.id)
elif filter_value.match_type == TreeNodeMatch.ANCESTORS:
return Q(tree_id=node.tree_id, lft__lt=node.lft, rght__gt=node.rght)
elif filter_value.match_type == TreeNodeMatch.PARENT:
return Q(id=node.parent_id) if node.parent_id else Q(pk__in=[])
return Q()
@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.')
class ArrayLookup(Generic[T]):
"""
Class for Array field lookups
"""
contains: list[T] | None = strawberry_django.filter_field(description='Contains the value')
contained_by: list[T] | None = strawberry_django.filter_field(description='Contained by the value')
overlap: list[T] | None = strawberry_django.filter_field(description='Overlaps with the value')
length: int | None = strawberry_django.filter_field(description='Length of the array')
@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.')
class IntegerArrayLookup(ArrayLookup[int]):
pass
@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.')
class FloatArrayLookup(ArrayLookup[float]):
pass
@strawberry.input(one_of=True, description='Lookup for Array fields. Only one of the lookup fields can be set.')
class StringArrayLookup(ArrayLookup[str]):
pass

View File

@ -1,209 +1,109 @@
from functools import partialmethod from dataclasses import dataclass
from typing import List from datetime import datetime
from typing import TypeVar, TYPE_CHECKING, Annotated
import django_filters
import strawberry import strawberry
import strawberry_django import strawberry_django
from django.core.exceptions import FieldDoesNotExist from strawberry import ID
from strawberry import auto from strawberry_django import FilterLookup, DatetimeFilterLookup
from ipam.fields import ASNField from core.graphql.filter_mixins import BaseFilterMixin, BaseObjectTypeFilterMixin, ChangeLogFilterMixin
from netbox.graphql.scalars import BigInt from extras.graphql.filter_mixins import CustomFieldsFilterMixin, JournalEntriesFilterMixin, TagsFilterMixin
from utilities.fields import ColorField, CounterCacheField from netbox.graphql.filter_lookups import IntegerLookup
from utilities.filters import *
__all__ = (
'DistanceFilterMixin',
'ImageAttachmentFilterMixin',
'NestedGroupModelFilterMixin',
'NetBoxModelFilterMixin',
'OrganizationalModelFilterMixin',
'PrimaryModelFilterMixin',
'SyncedDataFilterMixin',
'WeightFilterMixin',
)
T = TypeVar('T')
def map_strawberry_type(field): if TYPE_CHECKING:
should_create_function = False from .enums import *
attr_type = None from core.graphql.filters import *
from extras.graphql.filters import *
# NetBox Filter types - put base classes after derived classes
if isinstance(field, ContentTypeFilter):
should_create_function = True
attr_type = str | None
elif isinstance(field, MultiValueArrayFilter):
pass
elif isinstance(field, MultiValueCharFilter):
# Note: Need to use the legacy FilterLookup from filters, not from
# strawberry_django.FilterLookup as we currently have USE_DEPRECATED_FILTERS
attr_type = strawberry_django.filters.FilterLookup[str] | None
elif isinstance(field, MultiValueDateFilter):
attr_type = auto
elif isinstance(field, MultiValueDateTimeFilter):
attr_type = auto
elif isinstance(field, MultiValueDecimalFilter):
pass
elif isinstance(field, MultiValueMACAddressFilter):
should_create_function = True
attr_type = List[str] | None
elif isinstance(field, MultiValueNumberFilter):
should_create_function = True
attr_type = List[str] | None
elif isinstance(field, MultiValueTimeFilter):
pass
elif isinstance(field, MultiValueWWNFilter):
should_create_function = True
attr_type = List[str] | None
elif isinstance(field, NullableCharFieldFilter):
pass
elif isinstance(field, NumericArrayFilter):
should_create_function = True
attr_type = int | None
elif isinstance(field, TreeNodeMultipleChoiceFilter):
should_create_function = True
attr_type = List[str] | None
# From django_filters - ordering of these matters as base classes must
# come after derived classes so the base class doesn't get matched first
# a pass for the check (no attr_type) means we don't currently handle
# or use that type
elif issubclass(type(field), django_filters.OrderingFilter):
pass
elif issubclass(type(field), django_filters.BaseRangeFilter):
pass
elif issubclass(type(field), django_filters.BaseInFilter):
pass
elif issubclass(type(field), django_filters.LookupChoiceFilter):
pass
elif issubclass(type(field), django_filters.AllValuesMultipleFilter):
pass
elif issubclass(type(field), django_filters.AllValuesFilter):
pass
elif issubclass(type(field), django_filters.TimeRangeFilter):
pass
elif issubclass(type(field), django_filters.IsoDateTimeFromToRangeFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.DateTimeFromToRangeFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.DateFromToRangeFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.DateRangeFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.RangeFilter):
pass
elif issubclass(type(field), django_filters.NumericRangeFilter):
pass
elif issubclass(type(field), django_filters.NumberFilter):
should_create_function = True
attr_type = int | None
elif issubclass(type(field), django_filters.ModelMultipleChoiceFilter):
should_create_function = True
attr_type = List[str] | None
elif issubclass(type(field), django_filters.ModelChoiceFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.DurationFilter):
pass
elif issubclass(type(field), django_filters.IsoDateTimeFilter):
pass
elif issubclass(type(field), django_filters.DateTimeFilter):
attr_type = auto
elif issubclass(type(field), django_filters.TimeFilter):
attr_type = auto
elif issubclass(type(field), django_filters.DateFilter):
attr_type = auto
elif issubclass(type(field), django_filters.TypedMultipleChoiceFilter):
pass
elif issubclass(type(field), django_filters.MultipleChoiceFilter):
attr_type = str | None
elif issubclass(type(field), django_filters.TypedChoiceFilter):
pass
elif issubclass(type(field), django_filters.ChoiceFilter):
pass
elif issubclass(type(field), django_filters.BooleanFilter):
should_create_function = True
attr_type = bool | None
elif issubclass(type(field), django_filters.UUIDFilter):
should_create_function = True
attr_type = str | None
elif issubclass(type(field), django_filters.CharFilter):
# looks like only used by 'q'
should_create_function = True
attr_type = str | None
return should_create_function, attr_type
def autotype_decorator(filterset): class NetBoxModelFilterMixin(
""" ChangeLogFilterMixin,
Decorator used to auto creates a dataclass used by Strawberry based on a filterset. CustomFieldsFilterMixin,
Must go after the Strawberry decorator as follows: JournalEntriesFilterMixin,
TagsFilterMixin,
@strawberry_django.filter(models.Example, lookups=True) BaseObjectTypeFilterMixin,
@autotype_decorator(filtersets.ExampleFilterSet) ):
class ExampleFilter(BaseFilterMixin): pass
pass
The Filter itself must be derived from BaseFilterMixin. For items listed in meta.fields
of the filterset, usually just a type specifier is generated, so for
`fields = [created, ]` the dataclass would be:
class ExampleFilter(BaseFilterMixin):
created: auto
For other filter fields a function needs to be created for Strawberry with the
naming convention `filter_{fieldname}` which is auto detected and called by
Strawberry, this function uses the filterset to handle the query.
"""
def create_attribute_and_function(cls, fieldname, attr_type, should_create_function):
if fieldname not in cls.__annotations__ and attr_type:
cls.__annotations__[fieldname] = attr_type
filter_name = f"filter_{fieldname}"
if should_create_function and not hasattr(cls, filter_name):
filter_by_filterset = getattr(cls, 'filter_by_filterset')
setattr(cls, filter_name, partialmethod(filter_by_filterset, key=fieldname))
def wrapper(cls):
cls.filterset = filterset
fields = filterset.get_fields()
model = filterset._meta.model
for fieldname in fields.keys():
should_create_function = False
attr_type = auto
if fieldname not in cls.__annotations__:
try:
field = model._meta.get_field(fieldname)
except FieldDoesNotExist:
continue
if isinstance(field, CounterCacheField):
should_create_function = True
attr_type = BigInt | None
elif isinstance(field, ASNField):
should_create_function = True
attr_type = List[str] | None
elif isinstance(field, ColorField):
should_create_function = True
attr_type = List[str] | None
create_attribute_and_function(cls, fieldname, attr_type, should_create_function)
declared_filters = filterset.declared_filters
for fieldname, field in declared_filters.items():
should_create_function, attr_type = map_strawberry_type(field)
if attr_type is None:
raise NotImplementedError(f"GraphQL Filter field unknown: {fieldname}: {field}")
create_attribute_and_function(cls, fieldname, attr_type, should_create_function)
return cls
return wrapper
@strawberry.input @dataclass
class BaseFilterMixin: class NestedGroupModelFilterMixin(NetBoxModelFilterMixin):
name: FilterLookup[str] | None = strawberry_django.filter_field()
slug: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
lft: IntegerLookup | None = strawberry_django.filter_field()
rght: IntegerLookup | None = strawberry_django.filter_field()
tree_id: IntegerLookup | None = strawberry_django.filter_field()
level: IntegerLookup | None = strawberry_django.filter_field()
parent_id: ID | None = strawberry_django.filter_field()
def filter_by_filterset(self, queryset, key):
filterset = self.filterset(data={key: getattr(self, key)}, queryset=queryset) @dataclass
if not filterset.is_valid(): class OrganizationalModelFilterMixin(
# We could raise validation error but strawberry logs it all to the ChangeLogFilterMixin,
# console i.e. raise ValidationError(f"{k}: {v[0]}") CustomFieldsFilterMixin,
return filterset.qs.none() TagsFilterMixin,
return filterset.qs BaseObjectTypeFilterMixin,
):
name: FilterLookup[str] | None = strawberry_django.filter_field()
slug: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()
@dataclass
class PrimaryModelFilterMixin(NetBoxModelFilterMixin):
description: FilterLookup[str] | None = strawberry_django.filter_field()
comments: FilterLookup[str] | None = strawberry_django.filter_field()
@dataclass
class ImageAttachmentFilterMixin(BaseFilterMixin):
images: Annotated['ImageAttachmentFilter', strawberry.lazy('extras.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@dataclass
class WeightFilterMixin(BaseFilterMixin):
weight: FilterLookup[float] | None = strawberry_django.filter_field()
weight_unit: Annotated['WeightUnitEnum', strawberry.lazy('netbox.graphql.enums')] | None = (
strawberry_django.filter_field()
)
@dataclass
class SyncedDataFilterMixin(BaseFilterMixin):
data_source: Annotated['DataSourceFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
data_source_id: FilterLookup[int] | None = strawberry_django.filter_field()
data_file: Annotated['DataFileFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
data_file_id: FilterLookup[int] | None = strawberry_django.filter_field()
data_path: FilterLookup[str] | None = strawberry_django.filter_field()
auto_sync_enabled: FilterLookup[bool] | None = strawberry_django.filter_field()
data_synced: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
@dataclass
class DistanceFilterMixin(BaseFilterMixin):
distance: FilterLookup[float] | None = strawberry_django.filter_field()
distance_unit: Annotated['DistanceUnitEnum', strawberry.lazy('netbox.graphql.enums')] | None = (
strawberry_django.filter_field()
)

View File

@ -8,6 +8,7 @@ from extras.graphql.mixins import CustomFieldsMixin, JournalEntriesMixin, TagsMi
__all__ = ( __all__ = (
'BaseObjectType', 'BaseObjectType',
'ContentTypeType',
'ObjectType', 'ObjectType',
'OrganizationalObjectType', 'OrganizationalObjectType',
'NetBoxObjectType', 'NetBoxObjectType',

View File

@ -787,7 +787,6 @@ LOCALE_PATHS = (
STRAWBERRY_DJANGO = { STRAWBERRY_DJANGO = {
"DEFAULT_PK_FIELD_NAME": "id", "DEFAULT_PK_FIELD_NAME": "id",
"TYPE_DESCRIPTION_FROM_MODEL_DOCSTRING": True, "TYPE_DESCRIPTION_FROM_MODEL_DOCSTRING": True,
"USE_DEPRECATED_FILTERS": True,
} }
# #

View File

@ -99,8 +99,8 @@ class GraphQLAPITestCase(APITestCase):
# Test OR logic # Test OR logic
query = """{ query = """{
location_list( filters: { location_list( filters: {
status: \"""" + LocationStatusChoices.STATUS_PLANNED + """\", status: STATUS_PLANNED,
OR: {status: \"""" + LocationStatusChoices.STATUS_STAGING + """\"} OR: {status: STATUS_STAGING}
}) { }) {
id site {id} id site {id}
} }

View File

@ -0,0 +1,9 @@
import strawberry
from tenancy.choices import *
__all__ = (
'ContactPriorityEnum',
)
ContactPriorityEnum = strawberry.enum(ContactPriorityChoices.as_enum())

View File

@ -0,0 +1,38 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry import ID
from core.graphql.filter_mixins import BaseFilterMixin
if TYPE_CHECKING:
from netbox.graphql.filter_lookups import TreeNodeFilter
from .filters import ContactFilter, TenantFilter, TenantGroupFilter
__all__ = (
'ContactFilterMixin',
'TenancyFilterMixin',
)
@dataclass
class ContactFilterMixin(BaseFilterMixin):
contacts: Annotated['ContactFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@dataclass
class TenancyFilterMixin(BaseFilterMixin):
tenant: Annotated['TenantFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tenant_id: ID | None = strawberry_django.filter_field()
tenant_group: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tenant_group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,7 +1,49 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
from tenancy import filtersets, models import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import ChangeLogFilterMixin
from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin
from netbox.graphql.filter_mixins import (
NestedGroupModelFilterMixin,
OrganizationalModelFilterMixin,
PrimaryModelFilterMixin,
)
from tenancy import models
from .filter_mixins import ContactFilterMixin
if TYPE_CHECKING:
from core.graphql.filters import ContentTypeFilter
from circuits.graphql.filters import CircuitFilter
from dcim.graphql.filters import (
CableFilter,
DeviceFilter,
LocationFilter,
PowerFeedFilter,
RackFilter,
RackReservationFilter,
SiteFilter,
VirtualDeviceContextFilter,
)
from ipam.graphql.filters import (
AggregateFilter,
ASNFilter,
ASNRangeFilter,
IPAddressFilter,
IPRangeFilter,
PrefixFilter,
RouteTargetFilter,
VLANFilter,
VRFFilter,
)
from netbox.graphql.filter_lookups import TreeNodeFilter
from wireless.graphql.filters import WirelessLANFilter, WirelessLinkFilter
from virtualization.graphql.filters import ClusterFilter, VirtualMachineFilter
from vpn.graphql.filters import L2VPNFilter, TunnelFilter
from .enums import *
__all__ = ( __all__ = (
'TenantFilter', 'TenantFilter',
@ -14,36 +56,132 @@ __all__ = (
@strawberry_django.filter(models.Tenant, lookups=True) @strawberry_django.filter(models.Tenant, lookups=True)
@autotype_decorator(filtersets.TenantFilterSet) class TenantFilter(PrimaryModelFilterMixin, ContactFilterMixin):
class TenantFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
group: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
asns: Annotated['ASNFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
circuits: Annotated['CircuitFilter', strawberry.lazy('circuits.graphql.filters')] | None = (
strawberry_django.filter_field()
)
sites: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
vlans: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
wireless_lans: Annotated['WirelessLANFilter', strawberry.lazy('wireless.graphql.filters')] | None = (
strawberry_django.filter_field()
)
route_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
locations: Annotated['LocationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
ip_ranges: Annotated['IPRangeFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
rackreservations: Annotated['RackReservationFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
racks: Annotated['RackFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
vdcs: Annotated['VirtualDeviceContextFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
prefixes: Annotated['PrefixFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
cables: Annotated['CableFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
virtual_machines: Annotated['VirtualMachineFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
vrfs: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
asn_ranges: Annotated['ASNRangeFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
wireless_links: Annotated['WirelessLinkFilter', strawberry.lazy('wireless.graphql.filters')] | None = (
strawberry_django.filter_field()
)
aggregates: Annotated['AggregateFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
power_feeds: Annotated['PowerFeedFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
devices: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tunnels: Annotated['TunnelFilter', strawberry.lazy('vpn.graphql.filters')] | None = strawberry_django.filter_field()
ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
clusters: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
l2vpns: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.TenantGroup, lookups=True) @strawberry_django.filter(models.TenantGroup, lookups=True)
@autotype_decorator(filtersets.TenantGroupFilterSet) class TenantGroupFilter(OrganizationalModelFilterMixin):
class TenantGroupFilter(BaseFilterMixin): parent: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
parent_id: ID | None = strawberry.UNSET
tenants: Annotated['TenantFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
children: Annotated['TenantGroupFilter', strawberry.lazy('tenancy.graphql.filters'), True] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.Contact, lookups=True) @strawberry_django.filter(models.Contact, lookups=True)
@autotype_decorator(filtersets.ContactFilterSet) class ContactFilter(PrimaryModelFilterMixin):
class ContactFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass title: FilterLookup[str] | None = strawberry_django.filter_field()
phone: FilterLookup[str] | None = strawberry_django.filter_field()
email: FilterLookup[str] | None = strawberry_django.filter_field()
address: FilterLookup[str] | None = strawberry_django.filter_field()
link: FilterLookup[str] | None = strawberry_django.filter_field()
group: Annotated['ContactGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: Annotated['TreeNodeFilter', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
assignments: Annotated['ContactAssignmentFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ContactRole, lookups=True) @strawberry_django.filter(models.ContactRole, lookups=True)
@autotype_decorator(filtersets.ContactRoleFilterSet) class ContactRoleFilter(OrganizationalModelFilterMixin):
class ContactRoleFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.ContactGroup, lookups=True) @strawberry_django.filter(models.ContactGroup, lookups=True)
@autotype_decorator(filtersets.ContactGroupFilterSet) class ContactGroupFilter(NestedGroupModelFilterMixin):
class ContactGroupFilter(BaseFilterMixin): parent: Annotated['ContactGroupFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.ContactAssignment, lookups=True) @strawberry_django.filter(models.ContactAssignment, lookups=True)
@autotype_decorator(filtersets.ContactAssignmentFilterSet) class ContactAssignmentFilter(CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin):
class ContactAssignmentFilter(BaseFilterMixin): object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
object_id: ID | None = strawberry_django.filter_field()
contact: Annotated['ContactFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
contact_id: ID | None = strawberry_django.filter_field()
role: Annotated['ContactRoleFilter', strawberry.lazy('tenancy.graphql.filters')] | None = (
strawberry_django.filter_field()
)
role_id: ID | None = strawberry_django.filter_field()
priority: Annotated['ContactPriorityEnum', strawberry.lazy('tenancy.graphql.enums')] | None = (
strawberry_django.filter_field()
)

View File

@ -9,5 +9,4 @@ __all__ = (
@strawberry.type @strawberry.type
class ContactAssignmentsMixin: class ContactAssignmentsMixin:
assignments: List[Annotated["ContactAssignmentType", strawberry.lazy('tenancy.graphql.types')]] # noqa: F821 assignments: List[Annotated["ContactAssignmentType", strawberry.lazy('tenancy.graphql.types')]] # noqa: F821

View File

@ -1,4 +1,4 @@
from typing import Annotated, List from typing import Annotated, List, TYPE_CHECKING
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -6,8 +6,36 @@ import strawberry_django
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
from netbox.graphql.types import BaseObjectType, OrganizationalObjectType, NetBoxObjectType from netbox.graphql.types import BaseObjectType, OrganizationalObjectType, NetBoxObjectType
from tenancy import models from tenancy import models
from .mixins import ContactAssignmentsMixin
from .filters import * from .filters import *
from .mixins import ContactAssignmentsMixin
if TYPE_CHECKING:
from circuits.graphql.types import CircuitType
from dcim.graphql.types import (
CableType,
DeviceType,
LocationType,
PowerFeedType,
RackType,
RackReservationType,
SiteType,
VirtualDeviceContextType,
)
from ipam.graphql.types import (
AggregateType,
ASNType,
ASNRangeType,
IPAddressType,
IPRangeType,
PrefixType,
RouteTargetType,
VLANType,
VRFType,
)
from netbox.graphql.types import ContentTypeType
from wireless.graphql.types import WirelessLANType, WirelessLinkType
from virtualization.graphql.types import ClusterType, VirtualMachineType
from vpn.graphql.types import L2VPNType, TunnelType
__all__ = ( __all__ = (
'ContactAssignmentType', 'ContactAssignmentType',
@ -23,92 +51,70 @@ __all__ = (
# Tenants # Tenants
# #
@strawberry_django.type(
models.Tenant, @strawberry_django.type(models.Tenant, fields='__all__', filters=TenantFilter)
fields='__all__',
filters=TenantFilter
)
class TenantType(NetBoxObjectType): class TenantType(NetBoxObjectType):
group: Annotated["TenantGroupType", strawberry.lazy('tenancy.graphql.types')] | None group: Annotated['TenantGroupType', strawberry.lazy('tenancy.graphql.types')] | None
contacts: List[Annotated['ContactType', strawberry.lazy('tenancy.graphql.types')]]
asns: List[Annotated["ASNType", strawberry.lazy('ipam.graphql.types')]] asns: List[Annotated['ASNType', strawberry.lazy('ipam.graphql.types')]]
circuits: List[Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]] circuits: List[Annotated['CircuitType', strawberry.lazy('circuits.graphql.types')]]
sites: List[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]] sites: List[Annotated['SiteType', strawberry.lazy('dcim.graphql.types')]]
vlans: List[Annotated["VLANType", strawberry.lazy('ipam.graphql.types')]] vlans: List[Annotated['VLANType', strawberry.lazy('ipam.graphql.types')]]
wireless_lans: List[Annotated["WirelessLANType", strawberry.lazy('wireless.graphql.types')]] wireless_lans: List[Annotated['WirelessLANType', strawberry.lazy('wireless.graphql.types')]]
route_targets: List[Annotated["RouteTargetType", strawberry.lazy('ipam.graphql.types')]] route_targets: List[Annotated['RouteTargetType', strawberry.lazy('ipam.graphql.types')]]
locations: List[Annotated["LocationType", strawberry.lazy('dcim.graphql.types')]] locations: List[Annotated['LocationType', strawberry.lazy('dcim.graphql.types')]]
ip_ranges: List[Annotated["IPRangeType", strawberry.lazy('ipam.graphql.types')]] ip_ranges: List[Annotated['IPRangeType', strawberry.lazy('ipam.graphql.types')]]
rackreservations: List[Annotated["RackReservationType", strawberry.lazy('dcim.graphql.types')]] rackreservations: List[Annotated['RackReservationType', strawberry.lazy('dcim.graphql.types')]]
racks: List[Annotated["RackType", strawberry.lazy('dcim.graphql.types')]] racks: List[Annotated['RackType', strawberry.lazy('dcim.graphql.types')]]
vdcs: List[Annotated["VirtualDeviceContextType", strawberry.lazy('dcim.graphql.types')]] vdcs: List[Annotated['VirtualDeviceContextType', strawberry.lazy('dcim.graphql.types')]]
prefixes: List[Annotated["PrefixType", strawberry.lazy('ipam.graphql.types')]] prefixes: List[Annotated['PrefixType', strawberry.lazy('ipam.graphql.types')]]
cables: List[Annotated["CableType", strawberry.lazy('dcim.graphql.types')]] cables: List[Annotated['CableType', strawberry.lazy('dcim.graphql.types')]]
virtual_machines: List[Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]] virtual_machines: List[Annotated['VirtualMachineType', strawberry.lazy('virtualization.graphql.types')]]
vrfs: List[Annotated["VRFType", strawberry.lazy('ipam.graphql.types')]] vrfs: List[Annotated['VRFType', strawberry.lazy('ipam.graphql.types')]]
asn_ranges: List[Annotated["ASNRangeType", strawberry.lazy('ipam.graphql.types')]] asn_ranges: List[Annotated['ASNRangeType', strawberry.lazy('ipam.graphql.types')]]
wireless_links: List[Annotated["WirelessLinkType", strawberry.lazy('wireless.graphql.types')]] wireless_links: List[Annotated['WirelessLinkType', strawberry.lazy('wireless.graphql.types')]]
aggregates: List[Annotated["AggregateType", strawberry.lazy('ipam.graphql.types')]] aggregates: List[Annotated['AggregateType', strawberry.lazy('ipam.graphql.types')]]
power_feeds: List[Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')]] power_feeds: List[Annotated['PowerFeedType', strawberry.lazy('dcim.graphql.types')]]
devices: List[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]] devices: List[Annotated['DeviceType', strawberry.lazy('dcim.graphql.types')]]
tunnels: List[Annotated["TunnelType", strawberry.lazy('vpn.graphql.types')]] tunnels: List[Annotated['TunnelType', strawberry.lazy('vpn.graphql.types')]]
ip_addresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]] ip_addresses: List[Annotated['IPAddressType', strawberry.lazy('ipam.graphql.types')]]
clusters: List[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]] clusters: List[Annotated['ClusterType', strawberry.lazy('virtualization.graphql.types')]]
l2vpns: List[Annotated["L2VPNType", strawberry.lazy('vpn.graphql.types')]] l2vpns: List[Annotated['L2VPNType', strawberry.lazy('vpn.graphql.types')]]
@strawberry_django.type( @strawberry_django.type(models.TenantGroup, fields='__all__', filters=TenantGroupFilter)
models.TenantGroup,
fields='__all__',
filters=TenantGroupFilter
)
class TenantGroupType(OrganizationalObjectType): class TenantGroupType(OrganizationalObjectType):
parent: Annotated["TenantGroupType", strawberry.lazy('tenancy.graphql.types')] | None parent: Annotated['TenantGroupType', strawberry.lazy('tenancy.graphql.types')] | None
tenants: List[TenantType] tenants: List[TenantType]
children: List[Annotated["TenantGroupType", strawberry.lazy('tenancy.graphql.types')]] children: List[Annotated['TenantGroupType', strawberry.lazy('tenancy.graphql.types')]]
# #
# Contacts # Contacts
# #
@strawberry_django.type(
models.Contact, @strawberry_django.type(models.Contact, fields='__all__', filters=ContactFilter)
fields='__all__',
filters=ContactFilter
)
class ContactType(ContactAssignmentsMixin, NetBoxObjectType): class ContactType(ContactAssignmentsMixin, NetBoxObjectType):
group: Annotated["ContactGroupType", strawberry.lazy('tenancy.graphql.types')] | None group: Annotated['ContactGroupType', strawberry.lazy('tenancy.graphql.types')] | None
@strawberry_django.type( @strawberry_django.type(models.ContactRole, fields='__all__', filters=ContactRoleFilter)
models.ContactRole,
fields='__all__',
filters=ContactRoleFilter
)
class ContactRoleType(ContactAssignmentsMixin, OrganizationalObjectType): class ContactRoleType(ContactAssignmentsMixin, OrganizationalObjectType):
pass pass
@strawberry_django.type( @strawberry_django.type(models.ContactGroup, fields='__all__', filters=ContactGroupFilter)
models.ContactGroup,
fields='__all__',
filters=ContactGroupFilter
)
class ContactGroupType(OrganizationalObjectType): class ContactGroupType(OrganizationalObjectType):
parent: Annotated["ContactGroupType", strawberry.lazy('tenancy.graphql.types')] | None parent: Annotated['ContactGroupType', strawberry.lazy('tenancy.graphql.types')] | None
contacts: List[ContactType] contacts: List[ContactType]
children: List[Annotated["ContactGroupType", strawberry.lazy('tenancy.graphql.types')]] children: List[Annotated['ContactGroupType', strawberry.lazy('tenancy.graphql.types')]]
@strawberry_django.type( @strawberry_django.type(models.ContactAssignment, fields='__all__', filters=ContactAssignmentFilter)
models.ContactAssignment,
fields='__all__',
filters=ContactAssignmentFilter
)
class ContactAssignmentType(CustomFieldsMixin, TagsMixin, BaseObjectType): class ContactAssignmentType(CustomFieldsMixin, TagsMixin, BaseObjectType):
object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None object_type: Annotated['ContentTypeType', strawberry.lazy('netbox.graphql.types')] | None
contact: Annotated["ContactType", strawberry.lazy('tenancy.graphql.types')] | None contact: Annotated['ContactType', strawberry.lazy('tenancy.graphql.types')] | None
role: Annotated["ContactRoleType", strawberry.lazy('tenancy.graphql.types')] | None role: Annotated['ContactRoleType', strawberry.lazy('tenancy.graphql.types')] | None

View File

@ -1,7 +1,12 @@
import strawberry_django from datetime import datetime
from typing import Annotated
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
from users import filtersets, models import strawberry_django
from strawberry_django import DatetimeFilterLookup, FilterLookup
from core.graphql.filter_mixins import BaseObjectTypeFilterMixin
from users import models
__all__ = ( __all__ = (
'GroupFilter', 'GroupFilter',
@ -10,12 +15,20 @@ __all__ = (
@strawberry_django.filter(models.Group, lookups=True) @strawberry_django.filter(models.Group, lookups=True)
@autotype_decorator(filtersets.GroupFilterSet) class GroupFilter(BaseObjectTypeFilterMixin):
class GroupFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass description: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.User, lookups=True) @strawberry_django.filter(models.User, lookups=True)
@autotype_decorator(filtersets.UserFilterSet) class UserFilter(BaseObjectTypeFilterMixin):
class UserFilter(BaseFilterMixin): username: FilterLookup[str] | None = strawberry_django.filter_field()
pass first_name: FilterLookup[str] | None = strawberry_django.filter_field()
last_name: FilterLookup[str] | None = strawberry_django.filter_field()
email: FilterLookup[str] | None = strawberry_django.filter_field()
is_superuser: FilterLookup[bool] | None = strawberry_django.filter_field()
is_staff: FilterLookup[bool] | None = strawberry_django.filter_field()
is_active: FilterLookup[bool] | None = strawberry_django.filter_field()
date_joined: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
last_login: DatetimeFilterLookup[datetime] | None = strawberry_django.filter_field()
groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()

View File

@ -1,3 +1,5 @@
import enum
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -65,6 +67,23 @@ class ChoiceSet(metaclass=ChoiceSetMeta):
def values(cls): def values(cls):
return [c[0] for c in unpack_grouped_choices(cls._choices)] return [c[0] for c in unpack_grouped_choices(cls._choices)]
@classmethod
def as_enum(cls, name=None):
"""
Return the ChoiceSet as an Enum. If no name is provided, "Choices" will be stripped from the class name (if
present) and "Enum" will be appended. For example, "CircuitStatusChoices" will become "CircuitStatusEnum".
"""
name = name or f"{cls.__name__.split('Choices')[0]}Enum"
data = {}
choices = cls.values()
for attr in dir(cls):
value = getattr(cls, attr)
if attr.isupper() and value in choices:
data[attr] = value
return enum.Enum(name, data)
def unpack_grouped_choices(choices): def unpack_grouped_choices(choices):
""" """

View File

@ -0,0 +1,11 @@
import strawberry
from virtualization.choices import *
__all__ = (
'ClusterStatusEnum',
'VirtualMachineStatusEnum',
)
ClusterStatusEnum = strawberry.enum(ClusterStatusChoices.as_enum())
VirtualMachineStatusEnum = strawberry.enum(VirtualMachineStatusChoices.as_enum())

View File

@ -0,0 +1,26 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry import ID
from strawberry_django import FilterLookup
from netbox.graphql.filter_mixins import NetBoxModelFilterMixin
if TYPE_CHECKING:
from .filters import VirtualMachineFilter
__all__ = (
'VMComponentFilterMixin',
)
@dataclass
class VMComponentFilterMixin(NetBoxModelFilterMixin):
virtual_manchine: Annotated['VirtualMachineFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
virtual_machine_id: ID | None = strawberry_django.filter_field()
name: FilterLookup[str] | None = strawberry_django.filter_field()
description: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,7 +1,33 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
from virtualization import filtersets, models import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from dcim.graphql.filter_mixins import InterfaceBaseFilterMixin, RenderConfigFilterMixin, ScopedFilterMixin
from extras.graphql.filter_mixins import ConfigContextFilterMixin
from netbox.graphql.filter_mixins import (
ImageAttachmentFilterMixin,
OrganizationalModelFilterMixin,
PrimaryModelFilterMixin,
)
from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
from virtualization import models
from virtualization.graphql.filter_mixins import VMComponentFilterMixin
if TYPE_CHECKING:
from .enums import *
from netbox.graphql.filter_lookups import FloatLookup, IntegerLookup
from dcim.graphql.filters import DeviceFilter, DeviceRoleFilter, MACAddressFilter, PlatformFilter, SiteFilter
from ipam.graphql.filters import (
FHRPGroupAssignmentFilter,
IPAddressFilter,
ServiceFilter,
VLANGroupFilter,
VRFFilter,
)
from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter
__all__ = ( __all__ = (
'ClusterFilter', 'ClusterFilter',
@ -14,36 +40,119 @@ __all__ = (
@strawberry_django.filter(models.Cluster, lookups=True) @strawberry_django.filter(models.Cluster, lookups=True)
@autotype_decorator(filtersets.ClusterFilterSet) class ClusterFilter(ContactFilterMixin, ScopedFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class ClusterFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass type: Annotated['ClusterTypeFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
type_id: ID | None = strawberry_django.filter_field()
group: Annotated['ClusterGroupFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
status: Annotated['ClusterStatusEnum', strawberry.lazy('virtualization.graphql.enums')] | None = (
strawberry_django.filter_field()
)
vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.ClusterGroup, lookups=True) @strawberry_django.filter(models.ClusterGroup, lookups=True)
@autotype_decorator(filtersets.ClusterGroupFilterSet) class ClusterGroupFilter(ContactFilterMixin, OrganizationalModelFilterMixin):
class ClusterGroupFilter(BaseFilterMixin): vlan_groups: Annotated['VLANGroupFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
@strawberry_django.filter(models.ClusterType, lookups=True) @strawberry_django.filter(models.ClusterType, lookups=True)
@autotype_decorator(filtersets.ClusterTypeFilterSet) class ClusterTypeFilter(OrganizationalModelFilterMixin):
class ClusterTypeFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.VirtualMachine, lookups=True) @strawberry_django.filter(models.VirtualMachine, lookups=True)
@autotype_decorator(filtersets.VirtualMachineFilterSet) class VirtualMachineFilter(
class VirtualMachineFilter(BaseFilterMixin): ContactFilterMixin,
pass ImageAttachmentFilterMixin,
RenderConfigFilterMixin,
ConfigContextFilterMixin,
TenancyFilterMixin,
PrimaryModelFilterMixin,
):
name: FilterLookup[str] | None = strawberry_django.filter_field()
site: Annotated['SiteFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
site_id: ID | None = strawberry_django.filter_field()
cluster: Annotated['ClusterFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
cluster_id: ID | None = strawberry_django.filter_field()
device: Annotated['DeviceFilter', strawberry.lazy('dcim.graphql.filters')] | None = strawberry_django.filter_field()
device_id: ID | None = strawberry_django.filter_field()
platform: Annotated['PlatformFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
platform_id: ID | None = strawberry_django.filter_field()
status: Annotated['VirtualMachineStatusEnum', strawberry.lazy('virtualization.graphql.enums')] | None = (
strawberry_django.filter_field()
)
role: Annotated['DeviceRoleFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
role_id: ID | None = strawberry_django.filter_field()
primary_ip4: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip4_id: ID | None = strawberry_django.filter_field()
primary_ip6: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
primary_ip6_id: ID | None = strawberry_django.filter_field()
vcpus: Annotated['FloatLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
memory: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
disk: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
serial: FilterLookup[str] | None = strawberry_django.filter_field()
interface_count: FilterLookup[int] | None = strawberry_django.filter_field()
virtual_disk_count: FilterLookup[int] | None = strawberry_django.filter_field()
interfaces: Annotated['VMInterfaceFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
services: Annotated['ServiceFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
virtual_disks: Annotated['VirtualDiskFilter', strawberry.lazy('virtualization.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VMInterface, lookups=True) @strawberry_django.filter(models.VMInterface, lookups=True)
@autotype_decorator(filtersets.VMInterfaceFilterSet) class VMInterfaceFilter(VMComponentFilterMixin, InterfaceBaseFilterMixin):
class VMInterfaceFilter(BaseFilterMixin): ip_addresses: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
pass strawberry_django.filter_field()
)
vrf: Annotated['VRFFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vrf_id: ID | None = strawberry_django.filter_field()
fhrp_group_assignments: Annotated['FHRPGroupAssignmentFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tunnel_terminations: Annotated['TunnelTerminationFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
l2vpn_terminations: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
mac_addresses: Annotated['MACAddressFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.VirtualDisk, lookups=True) @strawberry_django.filter(models.VirtualDisk, lookups=True)
@autotype_decorator(filtersets.VirtualDiskFilterSet) class VirtualDiskFilter(VMComponentFilterMixin):
class VirtualDiskFilter(BaseFilterMixin): size: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
pass strawberry_django.filter_field()
)

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -10,6 +10,21 @@ from netbox.graphql.types import OrganizationalObjectType, NetBoxObjectType
from virtualization import models from virtualization import models
from .filters import * from .filters import *
if TYPE_CHECKING:
from dcim.graphql.types import (
DeviceRoleType,
DeviceType,
LocationType,
MACAddressType,
PlatformType,
RegionType,
SiteGroupType,
SiteType,
)
from extras.graphql.types import ConfigTemplateType
from ipam.graphql.types import IPAddressType, ServiceType, VLANTranslationPolicyType, VLANType, VRFType
from tenancy.graphql.types import TenantType
__all__ = ( __all__ = (
'ClusterType', 'ClusterType',
'ClusterGroupType', 'ClusterGroupType',
@ -30,7 +45,7 @@ class ComponentType(NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.Cluster, models.Cluster,
exclude=('scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'), exclude=['scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'],
filters=ClusterFilter filters=ClusterFilter
) )
class ClusterType(VLANGroupsMixin, NetBoxObjectType): class ClusterType(VLANGroupsMixin, NetBoxObjectType):

View File

@ -0,0 +1,31 @@
import strawberry
from vpn.choices import *
__all__ = (
'AuthenticationAlgorithmEnum',
'AuthenticationMethodEnum',
'DHGroupEnum',
'EncryptionAlgorithmEnum',
'IKEModeEnum',
'IKEVersionEnum',
'IPSecModeEnum',
'L2VPNTypeEnum',
'TunnelEncapsulationEnum',
'TunnelStatusEnum',
'TunnelTerminationRoleEnum',
'TunnelTerminationTypeEnum',
)
AuthenticationAlgorithmEnum = strawberry.enum(AuthenticationAlgorithmChoices.as_enum())
AuthenticationMethodEnum = strawberry.enum(AuthenticationMethodChoices.as_enum())
DHGroupEnum = strawberry.enum(DHGroupChoices.as_enum())
EncryptionAlgorithmEnum = strawberry.enum(EncryptionAlgorithmChoices.as_enum())
IKEModeEnum = strawberry.enum(IKEModeChoices.as_enum())
IKEVersionEnum = strawberry.enum(IKEVersionChoices.as_enum())
IPSecModeEnum = strawberry.enum(IPSecModeChoices.as_enum())
L2VPNTypeEnum = strawberry.enum(L2VPNTypeChoices.as_enum())
TunnelEncapsulationEnum = strawberry.enum(TunnelEncapsulationChoices.as_enum())
TunnelStatusEnum = strawberry.enum(TunnelStatusChoices.as_enum())
TunnelTerminationRoleEnum = strawberry.enum(TunnelTerminationRoleChoices.as_enum())
TunnelTerminationTypeEnum = strawberry.enum(TunnelTerminationTypeChoices.as_enum())

View File

@ -1,7 +1,21 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
from vpn import filtersets, models import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import BaseObjectTypeFilterMixin, ChangeLogFilterMixin
from extras.graphql.filter_mixins import CustomFieldsFilterMixin, TagsFilterMixin
from netbox.graphql.filter_mixins import NetBoxModelFilterMixin, OrganizationalModelFilterMixin, PrimaryModelFilterMixin
from tenancy.graphql.filter_mixins import ContactFilterMixin, TenancyFilterMixin
from vpn import models
if TYPE_CHECKING:
from core.graphql.filters import ContentTypeFilter
from ipam.graphql.filters import IPAddressFilter, RouteTargetFilter
from netbox.graphql.filter_lookups import IntegerLookup
from .enums import *
__all__ = ( __all__ = (
'TunnelGroupFilter', 'TunnelGroupFilter',
@ -18,60 +32,143 @@ __all__ = (
@strawberry_django.filter(models.TunnelGroup, lookups=True) @strawberry_django.filter(models.TunnelGroup, lookups=True)
@autotype_decorator(filtersets.TunnelGroupFilterSet) class TunnelGroupFilter(OrganizationalModelFilterMixin):
class TunnelGroupFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.TunnelTermination, lookups=True) @strawberry_django.filter(models.TunnelTermination, lookups=True)
@autotype_decorator(filtersets.TunnelTerminationFilterSet) class TunnelTerminationFilter(
class TunnelTerminationFilter(BaseFilterMixin): BaseObjectTypeFilterMixin, CustomFieldsFilterMixin, TagsFilterMixin, ChangeLogFilterMixin
pass ):
tunnel: Annotated['TunnelFilter', strawberry.lazy('vpn.graphql.filters')] | None = strawberry_django.filter_field()
tunnel_id: ID | None = strawberry_django.filter_field()
role: Annotated['TunnelTerminationRoleEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
termination_type: Annotated['TunnelTerminationTypeEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
termination_type_id: ID | None = strawberry_django.filter_field()
termination_id: ID | None = strawberry_django.filter_field()
outside_ip: Annotated['IPAddressFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
outside_ip_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.Tunnel, lookups=True) @strawberry_django.filter(models.Tunnel, lookups=True)
@autotype_decorator(filtersets.TunnelFilterSet) class TunnelFilter(TenancyFilterMixin, PrimaryModelFilterMixin):
class TunnelFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass status: Annotated['TunnelStatusEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
group: Annotated['TunnelGroupFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
encapsulation: Annotated['TunnelEncapsulationEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
ipsec_profile: Annotated['IPSecProfileFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
tunnel_id: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.IKEProposal, lookups=True) @strawberry_django.filter(models.IKEProposal, lookups=True)
@autotype_decorator(filtersets.IKEProposalFilterSet) class IKEProposalFilter(PrimaryModelFilterMixin):
class IKEProposalFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass authentication_method: Annotated['AuthenticationMethodEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
encryption_algorithm: Annotated['EncryptionAlgorithmEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
authentication_algorithm: Annotated['AuthenticationAlgorithmEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
group: Annotated['DHGroupEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
sa_lifetime: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.IKEPolicy, lookups=True) @strawberry_django.filter(models.IKEPolicy, lookups=True)
@autotype_decorator(filtersets.IKEPolicyFilterSet) class IKEPolicyFilter(PrimaryModelFilterMixin):
class IKEPolicyFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass version: Annotated['IKEVersionEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
mode: Annotated['IKEModeEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
proposals: Annotated['IKEProposalFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
preshared_key: FilterLookup[str] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.IPSecProposal, lookups=True) @strawberry_django.filter(models.IPSecProposal, lookups=True)
@autotype_decorator(filtersets.IPSecProposalFilterSet) class IPSecProposalFilter(PrimaryModelFilterMixin):
class IPSecProposalFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass encryption_algorithm: Annotated['EncryptionAlgorithmEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
authentication_algorithm: Annotated['AuthenticationAlgorithmEnum', strawberry.lazy('vpn.graphql.enums')] | None = (
strawberry_django.filter_field()
)
sa_lifetime_seconds: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
sa_lifetime_data: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.IPSecPolicy, lookups=True) @strawberry_django.filter(models.IPSecPolicy, lookups=True)
@autotype_decorator(filtersets.IPSecPolicyFilterSet) class IPSecPolicyFilter(PrimaryModelFilterMixin):
class IPSecPolicyFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass proposals: Annotated['IPSecProposalFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
pfs_group: Annotated['DHGroupEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
@strawberry_django.filter(models.IPSecProfile, lookups=True) @strawberry_django.filter(models.IPSecProfile, lookups=True)
@autotype_decorator(filtersets.IPSecProfileFilterSet) class IPSecProfileFilter(PrimaryModelFilterMixin):
class IPSecProfileFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass mode: Annotated['IPSecModeEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
ike_policy: Annotated['IKEPolicyFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
ike_policy_id: ID | None = strawberry_django.filter_field()
ipsec_policy: Annotated['IPSecPolicyFilter', strawberry.lazy('vpn.graphql.filters')] | None = (
strawberry_django.filter_field()
)
ipsec_policy_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.L2VPN, lookups=True) @strawberry_django.filter(models.L2VPN, lookups=True)
@autotype_decorator(filtersets.L2VPNFilterSet) class L2VPNFilter(ContactFilterMixin, TenancyFilterMixin, PrimaryModelFilterMixin):
class L2VPNFilter(BaseFilterMixin): name: FilterLookup[str] | None = strawberry_django.filter_field()
pass slug: FilterLookup[str] | None = strawberry_django.filter_field()
type: Annotated['L2VPNTypeEnum', strawberry.lazy('vpn.graphql.enums')] | None = strawberry_django.filter_field()
identifier: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
import_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
export_targets: Annotated['RouteTargetFilter', strawberry.lazy('ipam.graphql.filters')] | None = (
strawberry_django.filter_field()
)
@strawberry_django.filter(models.L2VPNTermination, lookups=True) @strawberry_django.filter(models.L2VPNTermination, lookups=True)
@autotype_decorator(filtersets.L2VPNTerminationFilterSet) class L2VPNTerminationFilter(NetBoxModelFilterMixin):
class L2VPNTerminationFilter(BaseFilterMixin): l2vpn: Annotated['L2VPNFilter', strawberry.lazy('vpn.graphql.filters')] | None = strawberry_django.filter_field()
pass l2vpn_id: ID | None = strawberry_django.filter_field()
assigned_object_type: Annotated['ContentTypeFilter', strawberry.lazy('core.graphql.filters')] | None = (
strawberry_django.filter_field()
)
assigned_object_id: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -8,6 +8,13 @@ from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObj
from vpn import models from vpn import models
from .filters import * from .filters import *
if TYPE_CHECKING:
from dcim.graphql.types import InterfaceType
from ipam.graphql.types import IPAddressType, RouteTargetType, VLANType
from netbox.graphql.types import ContentTypeType
from tenancy.graphql.types import TenantType
from virtualization.graphql.types import VMInterfaceType
__all__ = ( __all__ = (
'IKEPolicyType', 'IKEPolicyType',
'IKEProposalType', 'IKEProposalType',
@ -125,7 +132,7 @@ class L2VPNType(ContactsMixin, NetBoxObjectType):
@strawberry_django.type( @strawberry_django.type(
models.L2VPNTermination, models.L2VPNTermination,
exclude=('assigned_object_type', 'assigned_object_id'), exclude=['assigned_object_type', 'assigned_object_id'],
filters=L2VPNTerminationFilter filters=L2VPNTerminationFilter
) )
class L2VPNTerminationType(NetBoxObjectType): class L2VPNTerminationType(NetBoxObjectType):

View File

@ -0,0 +1,17 @@
import strawberry
from wireless.choices import *
__all__ = (
'WirelessAuthCipherEnum',
'WirelessAuthTypeEnum',
'WirelessChannelEnum',
'WirelessLANStatusEnum',
'WirelessRoleEnum',
)
WirelessAuthCipherEnum = strawberry.enum(WirelessAuthCipherChoices.as_enum())
WirelessAuthTypeEnum = strawberry.enum(WirelessAuthTypeChoices.as_enum())
WirelessChannelEnum = strawberry.enum(WirelessChannelChoices.as_enum())
WirelessLANStatusEnum = strawberry.enum(WirelessLANStatusChoices.as_enum())
WirelessRoleEnum = strawberry.enum(WirelessRoleChoices.as_enum())

View File

@ -0,0 +1,26 @@
from dataclasses import dataclass
from typing import Annotated, TYPE_CHECKING
import strawberry
import strawberry_django
from strawberry_django import FilterLookup
from core.graphql.filter_mixins import BaseFilterMixin
if TYPE_CHECKING:
from .enums import *
__all__ = (
'WirelessAuthenticationBaseFilterMixin',
)
@dataclass
class WirelessAuthenticationBaseFilterMixin(BaseFilterMixin):
auth_type: Annotated['WirelessAuthTypeEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
auth_cipher: Annotated['WirelessAuthCipherEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
auth_psk: FilterLookup[str] | None = strawberry_django.filter_field()

View File

@ -1,7 +1,20 @@
import strawberry_django from typing import Annotated, TYPE_CHECKING
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin import strawberry
from wireless import filtersets, models import strawberry_django
from strawberry.scalars import ID
from strawberry_django import FilterLookup
from dcim.graphql.filter_mixins import ScopedFilterMixin
from netbox.graphql.filter_mixins import DistanceFilterMixin, PrimaryModelFilterMixin, NestedGroupModelFilterMixin
from tenancy.graphql.filter_mixins import TenancyFilterMixin
from wireless import models
from .filter_mixins import WirelessAuthenticationBaseFilterMixin
if TYPE_CHECKING:
from dcim.graphql.filters import InterfaceFilter
from ipam.graphql.filters import VLANFilter
from .enums import *
__all__ = ( __all__ = (
'WirelessLANGroupFilter', 'WirelessLANGroupFilter',
@ -11,18 +24,45 @@ __all__ = (
@strawberry_django.filter(models.WirelessLANGroup, lookups=True) @strawberry_django.filter(models.WirelessLANGroup, lookups=True)
@autotype_decorator(filtersets.WirelessLANGroupFilterSet) class WirelessLANGroupFilter(NestedGroupModelFilterMixin):
class WirelessLANGroupFilter(BaseFilterMixin):
pass pass
@strawberry_django.filter(models.WirelessLAN, lookups=True) @strawberry_django.filter(models.WirelessLAN, lookups=True)
@autotype_decorator(filtersets.WirelessLANFilterSet) class WirelessLANFilter(
class WirelessLANFilter(BaseFilterMixin): WirelessAuthenticationBaseFilterMixin,
pass ScopedFilterMixin,
TenancyFilterMixin,
PrimaryModelFilterMixin
):
ssid: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['WirelessLANStatusEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)
group: Annotated['WirelessLANGroupFilter', strawberry.lazy('wireless.graphql.filters')] | None = (
strawberry_django.filter_field()
)
group_id: ID | None = strawberry_django.filter_field()
vlan: Annotated['VLANFilter', strawberry.lazy('ipam.graphql.filters')] | None = strawberry_django.filter_field()
vlan_id: ID | None = strawberry_django.filter_field()
@strawberry_django.filter(models.WirelessLink, lookups=True) @strawberry_django.filter(models.WirelessLink, lookups=True)
@autotype_decorator(filtersets.WirelessLinkFilterSet) class WirelessLinkFilter(
class WirelessLinkFilter(BaseFilterMixin): WirelessAuthenticationBaseFilterMixin,
pass DistanceFilterMixin,
TenancyFilterMixin,
PrimaryModelFilterMixin
):
interface_a: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
interface_a_id: ID | None = strawberry_django.filter_field()
interface_b: Annotated['InterfaceFilter', strawberry.lazy('dcim.graphql.filters')] | None = (
strawberry_django.filter_field()
)
interface_b_id: ID | None = strawberry_django.filter_field()
ssid: FilterLookup[str] | None = strawberry_django.filter_field()
status: Annotated['WirelessLANStatusEnum', strawberry.lazy('wireless.graphql.enums')] | None = (
strawberry_django.filter_field()
)

View File

@ -1,4 +1,4 @@
from typing import Annotated, List, Union from typing import Annotated, List, TYPE_CHECKING, Union
import strawberry import strawberry
import strawberry_django import strawberry_django
@ -7,6 +7,11 @@ from netbox.graphql.types import OrganizationalObjectType, NetBoxObjectType
from wireless import models from wireless import models
from .filters import * from .filters import *
if TYPE_CHECKING:
from dcim.graphql.types import DeviceType, InterfaceType, LocationType, RegionType, SiteGroupType, SiteType
from ipam.graphql.types import VLANType
from tenancy.graphql.types import TenantType
__all__ = ( __all__ = (
'WirelessLANType', 'WirelessLANType',
'WirelessLANGroupType', 'WirelessLANGroupType',
@ -28,7 +33,7 @@ class WirelessLANGroupType(OrganizationalObjectType):
@strawberry_django.type( @strawberry_django.type(
models.WirelessLAN, models.WirelessLAN,
exclude=('scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'), exclude=['scope_type', 'scope_id', '_location', '_region', '_site', '_site_group'],
filters=WirelessLANFilter filters=WirelessLANFilter
) )
class WirelessLANType(NetBoxObjectType): class WirelessLANType(NetBoxObjectType):