Use _list appendix for GraphQL list queries

This commit is contained in:
jeremystretch 2021-06-30 09:57:33 -04:00
parent 0d7309cb19
commit 728b3bac67
11 changed files with 81 additions and 82 deletions

View File

@ -42,8 +42,10 @@ The response will include the requested data formatted as JSON:
NetBox provides both a singular and plural query field for each object type: NetBox provides both a singular and plural query field for each object type:
* `object`: Returns a single object. Must specify the object's unique ID as `(id: 123)`. * `$OBJECT`: Returns a single object. Must specify the object's unique ID as `(id: 123)`.
* `objects`: Returns a list of objects, optionally filtered by given parameters. * `$OBJECT_list`: Returns a list of objects, optionally filtered by given parameters.
For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of fitlers) to fetch all devices.
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/). For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/).

View File

@ -6,16 +6,16 @@ from .types import *
class CircuitsQuery(graphene.ObjectType): class CircuitsQuery(graphene.ObjectType):
circuit = ObjectField(CircuitType) circuit = ObjectField(CircuitType)
circuits = ObjectListField(CircuitType) circuit_list = ObjectListField(CircuitType)
circuit_termination = ObjectField(CircuitTerminationType) circuit_termination = ObjectField(CircuitTerminationType)
circuit_terminations = ObjectListField(CircuitTerminationType) circuit_termination_list = ObjectListField(CircuitTerminationType)
circuit_type = ObjectField(CircuitTypeType) circuit_type = ObjectField(CircuitTypeType)
circuit_types = ObjectListField(CircuitTypeType) circuit_type_list = ObjectListField(CircuitTypeType)
provider = ObjectField(ProviderType) provider = ObjectField(ProviderType)
providers = ObjectListField(ProviderType) provider_list = ObjectListField(ProviderType)
provider_network = ObjectField(ProviderNetworkType) provider_network = ObjectField(ProviderNetworkType)
provider_networks = ObjectListField(ProviderNetworkType) provider_network_list = ObjectListField(ProviderNetworkType)

View File

@ -6,101 +6,100 @@ from .types import *
class DCIMQuery(graphene.ObjectType): class DCIMQuery(graphene.ObjectType):
cable = ObjectField(CableType) cable = ObjectField(CableType)
cables = ObjectListField(CableType) cable_list = ObjectListField(CableType)
console_port = ObjectField(ConsolePortType) console_port = ObjectField(ConsolePortType)
console_ports = ObjectListField(ConsolePortType) console_port_list = ObjectListField(ConsolePortType)
console_port_template = ObjectField(ConsolePortTemplateType) console_port_template = ObjectField(ConsolePortTemplateType)
console_port_templates = ObjectListField(ConsolePortTemplateType) console_port_template_list = ObjectListField(ConsolePortTemplateType)
console_server_port = ObjectField(ConsoleServerPortType) console_server_port = ObjectField(ConsoleServerPortType)
console_server_ports = ObjectListField(ConsoleServerPortType) console_server_port_list = ObjectListField(ConsoleServerPortType)
console_server_port_template = ObjectField(ConsoleServerPortTemplateType) console_server_port_template = ObjectField(ConsoleServerPortTemplateType)
console_server_port_templates = ObjectListField(ConsoleServerPortTemplateType) console_server_port_template_list = ObjectListField(ConsoleServerPortTemplateType)
device = ObjectField(DeviceType) device = ObjectField(DeviceType)
devices = ObjectListField(DeviceType) device_list = ObjectListField(DeviceType)
device_bay = ObjectField(DeviceBayType) device_bay = ObjectField(DeviceBayType)
device_bays = ObjectListField(DeviceBayType) device_bay_list = ObjectListField(DeviceBayType)
device_bay_template = ObjectField(DeviceBayTemplateType) device_bay_template = ObjectField(DeviceBayTemplateType)
device_bay_templates = ObjectListField(DeviceBayTemplateType) device_bay_template_list = ObjectListField(DeviceBayTemplateType)
device_role = ObjectField(DeviceRoleType) device_role = ObjectField(DeviceRoleType)
device_roles = ObjectListField(DeviceRoleType) device_role_list = ObjectListField(DeviceRoleType)
device_type = ObjectField(DeviceTypeType) device_type = ObjectField(DeviceTypeType)
device_types = ObjectListField(DeviceTypeType) device_type_list = ObjectListField(DeviceTypeType)
front_port = ObjectField(FrontPortType) front_port = ObjectField(FrontPortType)
front_ports = ObjectListField(FrontPortType) front_port_list = ObjectListField(FrontPortType)
front_port_template = ObjectField(FrontPortTemplateType) front_port_template = ObjectField(FrontPortTemplateType)
front_port_templates = ObjectListField(FrontPortTemplateType) front_port_template_list = ObjectListField(FrontPortTemplateType)
interface = ObjectField(InterfaceType) interface = ObjectField(InterfaceType)
interfaces = ObjectListField(InterfaceType) interface_list = ObjectListField(InterfaceType)
interface_template = ObjectField(InterfaceTemplateType) interface_template = ObjectField(InterfaceTemplateType)
interface_templates = ObjectListField(InterfaceTemplateType) interface_template_list = ObjectListField(InterfaceTemplateType)
inventory_item = ObjectField(InventoryItemType) inventory_item = ObjectField(InventoryItemType)
inventory_items = ObjectListField(InventoryItemType) inventory_item_list = ObjectListField(InventoryItemType)
location = ObjectField(LocationType) location = ObjectField(LocationType)
locations = ObjectListField(LocationType) location_list = ObjectListField(LocationType)
manufacturer = ObjectField(ManufacturerType) manufacturer = ObjectField(ManufacturerType)
manufacturers = ObjectListField(ManufacturerType) manufacturer_list = ObjectListField(ManufacturerType)
platform = ObjectField(PlatformType) platform = ObjectField(PlatformType)
platforms = ObjectListField(PlatformType) platform_list = ObjectListField(PlatformType)
power_feed = ObjectField(PowerFeedType) power_feed = ObjectField(PowerFeedType)
power_feeds = ObjectListField(PowerFeedType) power_feed_list = ObjectListField(PowerFeedType)
power_outlet = ObjectField(PowerOutletType) power_outlet = ObjectField(PowerOutletType)
power_outlets = ObjectListField(PowerOutletType) power_outlet_list = ObjectListField(PowerOutletType)
power_outlet_template = ObjectField(PowerOutletTemplateType) power_outlet_template = ObjectField(PowerOutletTemplateType)
power_outlet_templates = ObjectListField(PowerOutletTemplateType) power_outlet_template_list = ObjectListField(PowerOutletTemplateType)
power_panel = ObjectField(PowerPanelType) power_panel = ObjectField(PowerPanelType)
power_panels = ObjectListField(PowerPanelType) power_panel_list = ObjectListField(PowerPanelType)
power_port = ObjectField(PowerPortType) power_port = ObjectField(PowerPortType)
power_ports = ObjectListField(PowerPortType) power_port_list = ObjectListField(PowerPortType)
power_port_template = ObjectField(PowerPortTemplateType) power_port_template = ObjectField(PowerPortTemplateType)
power_port_templates = ObjectListField(PowerPortTemplateType) power_port_template_list = ObjectListField(PowerPortTemplateType)
rack = ObjectField(RackType) rack = ObjectField(RackType)
racks = ObjectListField(RackType) rack_list = ObjectListField(RackType)
rack_reservation = ObjectField(RackReservationType) rack_reservation = ObjectField(RackReservationType)
rack_reservations = ObjectListField(RackReservationType) rack_reservation_list = ObjectListField(RackReservationType)
rack_role = ObjectField(RackRoleType) rack_role = ObjectField(RackRoleType)
rack_roles = ObjectListField(RackRoleType) rack_role_list = ObjectListField(RackRoleType)
rear_port = ObjectField(RearPortType) rear_port = ObjectField(RearPortType)
rear_ports = ObjectListField(RearPortType) rear_port_list = ObjectListField(RearPortType)
rear_port_template = ObjectField(RearPortTemplateType) rear_port_template = ObjectField(RearPortTemplateType)
rear_port_templates = ObjectListField(RearPortTemplateType) rear_port_template_list = ObjectListField(RearPortTemplateType)
region = ObjectField(RegionType) region = ObjectField(RegionType)
regions = ObjectListField(RegionType) region_list = ObjectListField(RegionType)
site = ObjectField(SiteType) site = ObjectField(SiteType)
sites = ObjectListField(SiteType) site_list = ObjectListField(SiteType)
site_group = ObjectField(SiteGroupType) site_group = ObjectField(SiteGroupType)
site_groups = ObjectListField(SiteGroupType) site_group_list = ObjectListField(SiteGroupType)
virtual_chassis = ObjectField(VirtualChassisType) virtual_chassis = ObjectField(VirtualChassisType)
# TODO: Rectify list field name
virtual_chassis_list = ObjectListField(VirtualChassisType) virtual_chassis_list = ObjectListField(VirtualChassisType)

View File

@ -1549,8 +1549,6 @@ class VirtualChassisTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIV
model = VirtualChassis model = VirtualChassis
brief_fields = ['id', 'master', 'member_count', 'name', 'url'] brief_fields = ['id', 'master', 'member_count', 'name', 'url']
graphql_base_name_plural = 'virtual_chassis_list'
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
site = Site.objects.create(name='Test Site', slug='test-site') site = Site.objects.create(name='Test Site', slug='test-site')

View File

@ -6,25 +6,25 @@ from .types import *
class ExtrasQuery(graphene.ObjectType): class ExtrasQuery(graphene.ObjectType):
config_context = ObjectField(ConfigContextType) config_context = ObjectField(ConfigContextType)
config_contexts = ObjectListField(ConfigContextType) config_context_list = ObjectListField(ConfigContextType)
custom_field = ObjectField(CustomFieldType) custom_field = ObjectField(CustomFieldType)
custom_fields = ObjectListField(CustomFieldType) custom_field_list = ObjectListField(CustomFieldType)
custom_link = ObjectField(CustomLinkType) custom_link = ObjectField(CustomLinkType)
custom_links = ObjectListField(CustomLinkType) custom_link_list = ObjectListField(CustomLinkType)
export_template = ObjectField(ExportTemplateType) export_template = ObjectField(ExportTemplateType)
export_templates = ObjectListField(ExportTemplateType) export_template_list = ObjectListField(ExportTemplateType)
image_attachment = ObjectField(ImageAttachmentType) image_attachment = ObjectField(ImageAttachmentType)
image_attachments = ObjectListField(ImageAttachmentType) image_attachment_list = ObjectListField(ImageAttachmentType)
journal_entry = ObjectField(JournalEntryType) journal_entry = ObjectField(JournalEntryType)
journal_entries = ObjectListField(JournalEntryType) journal_entry_list = ObjectListField(JournalEntryType)
tag = ObjectField(TagType) tag = ObjectField(TagType)
tags = ObjectListField(TagType) tag_list = ObjectListField(TagType)
webhook = ObjectField(WebhookType) webhook = ObjectField(WebhookType)
webhooks = ObjectListField(WebhookType) webhook_list = ObjectListField(WebhookType)

View File

@ -6,31 +6,31 @@ from .types import *
class IPAMQuery(graphene.ObjectType): class IPAMQuery(graphene.ObjectType):
aggregate = ObjectField(AggregateType) aggregate = ObjectField(AggregateType)
aggregates = ObjectListField(AggregateType) aggregate_list = ObjectListField(AggregateType)
ip_address = ObjectField(IPAddressType) ip_address = ObjectField(IPAddressType)
ip_addresses = ObjectListField(IPAddressType) ip_address_list = ObjectListField(IPAddressType)
prefix = ObjectField(PrefixType) prefix = ObjectField(PrefixType)
prefixes = ObjectListField(PrefixType) prefix_list = ObjectListField(PrefixType)
rir = ObjectField(RIRType) rir = ObjectField(RIRType)
rirs = ObjectListField(RIRType) rir_list = ObjectListField(RIRType)
role = ObjectField(RoleType) role = ObjectField(RoleType)
roles = ObjectListField(RoleType) role_list = ObjectListField(RoleType)
route_target = ObjectField(RouteTargetType) route_target = ObjectField(RouteTargetType)
route_targets = ObjectListField(RouteTargetType) route_target_list = ObjectListField(RouteTargetType)
service = ObjectField(ServiceType) service = ObjectField(ServiceType)
services = ObjectListField(ServiceType) service_list = ObjectListField(ServiceType)
vlan = ObjectField(VLANType) vlan = ObjectField(VLANType)
vlans = ObjectListField(VLANType) vlan_list = ObjectListField(VLANType)
vlan_group = ObjectField(VLANGroupType) vlan_group = ObjectField(VLANGroupType)
vlan_groups = ObjectListField(VLANGroupType) vlan_group_list = ObjectListField(VLANGroupType)
vrf = ObjectField(VRFType) vrf = ObjectField(VRFType)
vrfs = ObjectListField(VRFType) vrf_list = ObjectListField(VRFType)

View File

@ -6,7 +6,7 @@ from .types import *
class TenancyQuery(graphene.ObjectType): class TenancyQuery(graphene.ObjectType):
tenant = ObjectField(TenantType) tenant = ObjectField(TenantType)
tenants = ObjectListField(TenantType) tenant_list = ObjectListField(TenantType)
tenant_group = ObjectField(TenantGroupType) tenant_group = ObjectField(TenantGroupType)
tenant_groups = ObjectListField(TenantGroupType) tenant_group_list = ObjectListField(TenantGroupType)

View File

@ -6,7 +6,7 @@ from .types import *
class UsersQuery(graphene.ObjectType): class UsersQuery(graphene.ObjectType):
group = ObjectField(GroupType) group = ObjectField(GroupType)
groups = ObjectListField(GroupType) group_list = ObjectListField(GroupType)
user = ObjectField(UserType) user = ObjectField(UserType)
users = ObjectListField(UserType) user_list = ObjectListField(UserType)

View File

@ -24,7 +24,7 @@ __all__ = (
# #
# REST API Tests # REST/GraphQL API Tests
# #
class APITestCase(ModelTestCase): class APITestCase(ModelTestCase):
@ -427,11 +427,13 @@ class APIViewTestCases:
class GraphQLTestCase(APITestCase): class GraphQLTestCase(APITestCase):
def _get_graphql_base_name(self, plural=False): def _get_graphql_base_name(self):
if plural: """
return getattr(self, 'graphql_base_name_plural', Return graphql_base_name, if set. Otherwise, construct the base name for the query
self.model._meta.verbose_name_plural.lower().replace(' ', '_')) field from the model's verbose name.
return getattr(self, 'graphql_base_name', self.model._meta.verbose_name.lower().replace(' ', '_')) """
base_name = self.model._meta.verbose_name.lower().replace(' ', '_')
return getattr(self, 'graphql_base_name', base_name)
def _build_query(self, name, **filters): def _build_query(self, name, **filters):
type_class = get_graphql_type_for_model(self.model) type_class = get_graphql_type_for_model(self.model)
@ -466,9 +468,9 @@ class APIViewTestCases:
@override_settings(LOGIN_REQUIRED=True) @override_settings(LOGIN_REQUIRED=True)
def test_graphql_get_object(self): def test_graphql_get_object(self):
url = reverse('graphql') url = reverse('graphql')
object_type = self._get_graphql_base_name() field_name = self._get_graphql_base_name()
object_id = self._get_queryset().first().pk object_id = self._get_queryset().first().pk
query = self._build_query(object_type, id=object_id) query = self._build_query(field_name, id=object_id)
# Non-authenticated requests should fail # Non-authenticated requests should fail
with disable_warnings('django.request'): with disable_warnings('django.request'):
@ -491,8 +493,8 @@ class APIViewTestCases:
@override_settings(LOGIN_REQUIRED=True) @override_settings(LOGIN_REQUIRED=True)
def test_graphql_list_objects(self): def test_graphql_list_objects(self):
url = reverse('graphql') url = reverse('graphql')
object_type = self._get_graphql_base_name(plural=True) field_name = f'{self._get_graphql_base_name()}_list'
query = self._build_query(object_type) query = self._build_query(field_name)
# Non-authenticated requests should fail # Non-authenticated requests should fail
with disable_warnings('django.request'): with disable_warnings('django.request'):
@ -511,7 +513,7 @@ class APIViewTestCases:
self.assertHttpStatus(response, status.HTTP_200_OK) self.assertHttpStatus(response, status.HTTP_200_OK)
data = json.loads(response.content) data = json.loads(response.content)
self.assertNotIn('errors', data) self.assertNotIn('errors', data)
self.assertGreater(len(data['data'][object_type]), 0) self.assertGreater(len(data['data'][field_name]), 0)
class APIViewTestCase( class APIViewTestCase(
GetObjectViewTestCase, GetObjectViewTestCase,

View File

@ -6,16 +6,16 @@ from .types import *
class VirtualizationQuery(graphene.ObjectType): class VirtualizationQuery(graphene.ObjectType):
cluster = ObjectField(ClusterType) cluster = ObjectField(ClusterType)
clusters = ObjectListField(ClusterType) cluster_list = ObjectListField(ClusterType)
cluster_group = ObjectField(ClusterGroupType) cluster_group = ObjectField(ClusterGroupType)
cluster_groups = ObjectListField(ClusterGroupType) cluster_group_list = ObjectListField(ClusterGroupType)
cluster_type = ObjectField(ClusterTypeType) cluster_type = ObjectField(ClusterTypeType)
cluster_types = ObjectListField(ClusterTypeType) cluster_type_list = ObjectListField(ClusterTypeType)
virtual_machine = ObjectField(VirtualMachineType) virtual_machine = ObjectField(VirtualMachineType)
virtual_machines = ObjectListField(VirtualMachineType) virtual_machine_list = ObjectListField(VirtualMachineType)
vm_interface = ObjectField(VMInterfaceType) vm_interface = ObjectField(VMInterfaceType)
vm_interfaces = ObjectListField(VMInterfaceType) vm_interface_list = ObjectListField(VMInterfaceType)

View File

@ -211,9 +211,7 @@ class VMInterfaceTest(APIViewTestCases.GraphQLTestCase, APIViewTestCases.APIView
bulk_update_data = { bulk_update_data = {
'description': 'New description', 'description': 'New description',
} }
graphql_base_name = 'vm_interface' graphql_base_name = 'vm_interface'
graphql_base_name_plural = 'vm_interfaces'
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):