Procházet zdrojové kódy

Use _list appendix for GraphQL list queries

jeremystretch před 4 roky
rodič
revize
728b3bac67

+ 4 - 2
docs/graphql-api/overview.md

@@ -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:
 
-* `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`: Returns a single object. Must specify the object's unique ID as `(id: 123)`.
+* `$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/).
 

+ 5 - 5
netbox/circuits/graphql/schema.py

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

+ 32 - 33
netbox/dcim/graphql/schema.py

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

+ 0 - 2
netbox/dcim/tests/test_api.py

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

+ 8 - 8
netbox/extras/graphql/schema.py

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

+ 10 - 10
netbox/ipam/graphql/schema.py

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

+ 2 - 2
netbox/tenancy/graphql/schema.py

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

+ 2 - 2
netbox/users/graphql/schema.py

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

+ 13 - 11
netbox/utilities/testing/api.py

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

+ 5 - 5
netbox/virtualization/graphql/schema.py

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

+ 0 - 2
netbox/virtualization/tests/test_api.py

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