diff --git a/netbox/circuits/graphql/types.py b/netbox/circuits/graphql/types.py index 29e7f8de3..d150d2b5c 100644 --- a/netbox/circuits/graphql/types.py +++ b/netbox/circuits/graphql/types.py @@ -74,7 +74,7 @@ class ProviderNetworkType(PrimaryObjectType): class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, ObjectType): circuit: Annotated['CircuitType', strawberry.lazy('circuits.graphql.types')] - @strawberry_django.field + @strawberry_django.field(prefetch_related='termination') def termination(self) -> Annotated[ Annotated['LocationType', strawberry.lazy('dcim.graphql.types')] | Annotated['RegionType', strawberry.lazy('dcim.graphql.types')] @@ -133,7 +133,7 @@ class CircuitGroupType(OrganizationalObjectType): class CircuitGroupAssignmentType(TagsMixin, BaseObjectType): group: Annotated['CircuitGroupType', strawberry.lazy('circuits.graphql.types')] - @strawberry_django.field + @strawberry_django.field(prefetch_related='member') def member(self) -> Annotated[ Annotated['CircuitType', strawberry.lazy('circuits.graphql.types')] | Annotated['VirtualCircuitType', strawberry.lazy('circuits.graphql.types')], diff --git a/netbox/dcim/graphql/types.py b/netbox/dcim/graphql/types.py index 6cbab28f2..6fc66af45 100644 --- a/netbox/dcim/graphql/types.py +++ b/netbox/dcim/graphql/types.py @@ -4,6 +4,7 @@ import strawberry import strawberry_django from django.db.models import Func, IntegerField +from circuits.models import CircuitTermination from core.graphql.mixins import ChangelogMixin from dcim import models from extras.graphql.mixins import ConfigContextMixin, ContactsMixin, ImageAttachmentsMixin @@ -17,6 +18,8 @@ from netbox.graphql.types import ( PrimaryObjectType, ) from users.graphql.mixins import OwnerMixin +from utilities.querysets import RestrictedPrefetch +from virtualization.models import Cluster from .filters import * from .mixins import CabledObjectMixin, PathEndpointMixin @@ -288,11 +291,11 @@ class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, Prima inventoryitems: list[Annotated["InventoryItemType", strawberry.lazy('dcim.graphql.types')]] vdcs: list[Annotated["VirtualDeviceContextType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='vc_master_for') def vc_master_for(self) -> Annotated["VirtualChassisType", strawberry.lazy('dcim.graphql.types')] | None: return self.vc_master_for if hasattr(self, 'vc_master_for') else None - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent_bay') def parent_bay(self) -> Annotated["DeviceBayType", strawberry.lazy('dcim.graphql.types')] | None: return self.parent_bay if hasattr(self, 'parent_bay') else None @@ -327,7 +330,7 @@ class InventoryItemTemplateType(ComponentTemplateType): role: Annotated['InventoryItemRoleType', strawberry.lazy('dcim.graphql.types')] | None manufacturer: Annotated['ManufacturerType', strawberry.lazy('dcim.graphql.types')] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated['InventoryItemTemplateType', strawberry.lazy('dcim.graphql.types')] | None: return self.parent @@ -430,7 +433,7 @@ class FrontPortTemplateType(ModularComponentTemplateType): class MACAddressType(PrimaryObjectType): mac_address: str - @strawberry_django.field + @strawberry_django.field(prefetch_related='assigned_object') def assigned_object(self) -> Annotated[ Annotated['InterfaceType', strawberry.lazy('dcim.graphql.types')] | Annotated['VMInterfaceType', strawberry.lazy('virtualization.graphql.types')], @@ -494,7 +497,7 @@ class InventoryItemType(ComponentType): child_items: list[Annotated['InventoryItemType', strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated['InventoryItemType', strawberry.lazy('dcim.graphql.types')] | None: return self.parent @@ -541,11 +544,20 @@ class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, Nested devices: list[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]] children: list[Annotated["LocationType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'cluster_set', info.context.request.user, 'view', queryset=Cluster.objects.all() + ), + ) def clusters(self) -> list[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: return self.cluster_set.all() - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'circuit_terminations', info.context.request.user, 'view', + queryset=CircuitTermination.objects.all() + ), + ) def circuit_terminations(self) -> list[ Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] ]: @@ -599,7 +611,7 @@ class ModuleBayType(ModularComponentType): installed_module: Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')] | None children: list[Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')] | None: return self.parent @@ -864,15 +876,24 @@ class RegionType(VLANGroupsMixin, ContactsMixin, NestedGroupObjectType): sites: list[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]] children: list[Annotated["RegionType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated["RegionType", strawberry.lazy('dcim.graphql.types')] | None: return self.parent - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'cluster_set', info.context.request.user, 'view', queryset=Cluster.objects.all() + ), + ) def clusters(self) -> list[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: return self.cluster_set.all() - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'circuit_terminations', info.context.request.user, 'view', + queryset=CircuitTermination.objects.all() + ), + ) def circuit_terminations(self) -> list[ Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] ]: @@ -903,11 +924,20 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, PrimaryObj clusters: list[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]] vlans: list[Annotated["VLANType", strawberry.lazy('ipam.graphql.types')]] - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'cluster_set', info.context.request.user, 'view', queryset=Cluster.objects.all() + ), + ) def clusters(self) -> list[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: return self.cluster_set.all() - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'circuit_terminations', info.context.request.user, 'view', + queryset=CircuitTermination.objects.all() + ), + ) def circuit_terminations(self) -> list[ Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] ]: @@ -925,15 +955,24 @@ class SiteGroupType(VLANGroupsMixin, ContactsMixin, NestedGroupObjectType): sites: list[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]] children: list[Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')] | None: return self.parent - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'cluster_set', info.context.request.user, 'view', queryset=Cluster.objects.all() + ), + ) def clusters(self) -> list[Annotated["ClusterType", strawberry.lazy('virtualization.graphql.types')]]: return self.cluster_set.all() - @strawberry_django.field + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'circuit_terminations', info.context.request.user, 'view', + queryset=CircuitTermination.objects.all() + ), + ) def circuit_terminations(self) -> list[ Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')] ]: diff --git a/netbox/extras/graphql/mixins.py b/netbox/extras/graphql/mixins.py index 96f9719a3..3a958d8bc 100644 --- a/netbox/extras/graphql/mixins.py +++ b/netbox/extras/graphql/mixins.py @@ -4,6 +4,9 @@ import strawberry import strawberry_django from strawberry.types import Info +from extras.models import ImageAttachment, JournalEntry +from utilities.querysets import RestrictedPrefetch + __all__ = ( 'ConfigContextMixin', 'ContactsMixin', @@ -50,16 +53,24 @@ class CustomFieldsMixin: @strawberry.type class ImageAttachmentsMixin: - @strawberry_django.field - def image_attachments(self, info: Info) -> list[Annotated['ImageAttachmentType', strawberry.lazy('.types')]]: - return self.images.restrict(info.context.request.user, 'view') + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'images', info.context.request.user, 'view', queryset=ImageAttachment.objects.all() + ), + ) + def image_attachments(self) -> list[Annotated['ImageAttachmentType', strawberry.lazy('.types')]]: + return self.images.all() @strawberry.type class JournalEntriesMixin: - @strawberry_django.field - def journal_entries(self, info: Info) -> list[Annotated['JournalEntryType', strawberry.lazy('.types')]]: + @strawberry_django.field( + prefetch_related=lambda info: RestrictedPrefetch( + 'journal_entries', info.context.request.user, 'view', queryset=JournalEntry.objects.all() + ), + ) + def journal_entries(self) -> list[Annotated['JournalEntryType', strawberry.lazy('.types')]]: return self.journal_entries.all() diff --git a/netbox/ipam/graphql/types.py b/netbox/ipam/graphql/types.py index 2bfdc7d65..31b93b419 100644 --- a/netbox/ipam/graphql/types.py +++ b/netbox/ipam/graphql/types.py @@ -128,7 +128,7 @@ class FHRPGroupType(IPAddressesMixin, PrimaryObjectType): class FHRPGroupAssignmentType(BaseObjectType): group: Annotated['FHRPGroupType', strawberry.lazy('ipam.graphql.types')] - @strawberry_django.field + @strawberry_django.field(prefetch_related='interface') def interface(self) -> Annotated[ Annotated['InterfaceType', strawberry.lazy('dcim.graphql.types')] | Annotated['VMInterfaceType', strawberry.lazy('virtualization.graphql.types')], @@ -153,7 +153,7 @@ class IPAddressType(ContactsMixin, BaseIPAddressFamilyType, PrimaryObjectType): tunnel_terminations: list[Annotated['TunnelTerminationType', strawberry.lazy('vpn.graphql.types')]] services: list[Annotated['ServiceType', strawberry.lazy('ipam.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='assigned_object') def assigned_object(self) -> Annotated[ Annotated['InterfaceType', strawberry.lazy('dcim.graphql.types')] | Annotated['FHRPGroupType', strawberry.lazy('ipam.graphql.types')] @@ -190,7 +190,7 @@ class PrefixType(ContactsMixin, BaseIPAddressFamilyType, PrimaryObjectType): vlan: Annotated['VLANType', strawberry.lazy('ipam.graphql.types')] | None role: Annotated['RoleType', strawberry.lazy('ipam.graphql.types')] | None - @strawberry_django.field + @strawberry_django.field(prefetch_related='scope') def scope(self) -> Annotated[ Annotated['LocationType', strawberry.lazy('dcim.graphql.types')] | Annotated['RegionType', strawberry.lazy('dcim.graphql.types')] @@ -252,7 +252,7 @@ class ServiceType(ContactsMixin, PrimaryObjectType): ports: list[int] ipaddresses: list[Annotated['IPAddressType', strawberry.lazy('ipam.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='parent') def parent(self) -> Annotated[ Annotated['DeviceType', strawberry.lazy('dcim.graphql.types')] | Annotated['VirtualMachineType', strawberry.lazy('virtualization.graphql.types')] @@ -291,7 +291,7 @@ class VLANType(PrimaryObjectType): interfaces_as_tagged: list[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]] vminterfaces_as_tagged: list[Annotated["VMInterfaceType", strawberry.lazy('virtualization.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='qinq_svlan') def qinq_svlan(self) -> Annotated["VLANType", strawberry.lazy('ipam.graphql.types')] | None: return self.qinq_svlan @@ -309,7 +309,7 @@ class VLANGroupType(OrganizationalObjectType): total_vlan_ids: BigInt tenant: Annotated['TenantType', strawberry.lazy('tenancy.graphql.types')] | None - @strawberry_django.field + @strawberry_django.field(prefetch_related='scope') def scope(self) -> Annotated[ Annotated['ClusterType', strawberry.lazy('virtualization.graphql.types')] | Annotated['ClusterGroupType', strawberry.lazy('virtualization.graphql.types')] diff --git a/netbox/virtualization/graphql/types.py b/netbox/virtualization/graphql/types.py index 96563aac8..81ef685a1 100644 --- a/netbox/virtualization/graphql/types.py +++ b/netbox/virtualization/graphql/types.py @@ -59,7 +59,7 @@ class ClusterType(ContactsMixin, VLANGroupsMixin, PrimaryObjectType): virtual_machines: list[Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]] devices: list[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='scope') def scope(self) -> Annotated[ Annotated['LocationType', strawberry.lazy('dcim.graphql.types')] | Annotated['RegionType', strawberry.lazy('dcim.graphql.types')] diff --git a/netbox/vpn/graphql/types.py b/netbox/vpn/graphql/types.py index d23c0a13b..40f125e83 100644 --- a/netbox/vpn/graphql/types.py +++ b/netbox/vpn/graphql/types.py @@ -145,7 +145,7 @@ class L2VPNType(ContactsMixin, PrimaryObjectType): class L2VPNTerminationType(NetBoxObjectType): l2vpn: Annotated["L2VPNType", strawberry.lazy('vpn.graphql.types')] - @strawberry_django.field + @strawberry_django.field(prefetch_related='assigned_object') def assigned_object(self) -> Annotated[ Annotated['InterfaceType', strawberry.lazy('dcim.graphql.types')] | Annotated['VLANType', strawberry.lazy('ipam.graphql.types')] diff --git a/netbox/wireless/graphql/types.py b/netbox/wireless/graphql/types.py index 2e7930074..557f32ce4 100644 --- a/netbox/wireless/graphql/types.py +++ b/netbox/wireless/graphql/types.py @@ -46,7 +46,7 @@ class WirelessLANType(PrimaryObjectType): interfaces: list[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]] - @strawberry_django.field + @strawberry_django.field(prefetch_related='scope') def scope(self) -> Annotated[ Annotated['LocationType', strawberry.lazy('dcim.graphql.types')] | Annotated['RegionType', strawberry.lazy('dcim.graphql.types')]