diff --git a/netbox/circuits/tests/test_api.py b/netbox/circuits/tests/test_api.py index a67dbc4ab..e6c98068f 100644 --- a/netbox/circuits/tests/test_api.py +++ b/netbox/circuits/tests/test_api.py @@ -56,6 +56,16 @@ class ProviderTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_providers_brief(self): + + url = reverse('circuits-api:provider-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_provider(self): data = { @@ -147,6 +157,16 @@ class CircuitTypeTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_circuittypes_brief(self): + + url = reverse('circuits-api:circuittype-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_circuittype(self): data = { @@ -216,6 +236,16 @@ class CircuitTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_circuits_brief(self): + + url = reverse('circuits-api:circuit-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['cid', 'id', 'url'] + ) + def test_create_circuit(self): data = { diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index a95743fd5..d0634e040 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -492,6 +492,15 @@ class ConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): fields = ['id', 'device', 'name', 'cs_port', 'connection_status', 'tags'] +class NestedConsolePortSerializer(TaggitSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail') + device = NestedDeviceSerializer(read_only=True) + + class Meta: + model = ConsolePort + fields = ['id', 'url', 'device', 'name'] + + # # Power outlets # @@ -529,6 +538,15 @@ class PowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): fields = ['id', 'device', 'name', 'power_outlet', 'connection_status', 'tags'] +class NestedPowerPortSerializer(TaggitSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail') + device = NestedDeviceSerializer(read_only=True) + + class Meta: + model = PowerPort + fields = ['id', 'url', 'device', 'name'] + + # # Interfaces # @@ -652,10 +670,11 @@ class DeviceBaySerializer(TaggitSerializer, ValidatedModelSerializer): class NestedDeviceBaySerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail') + device = NestedDeviceSerializer(read_only=True) class Meta: model = DeviceBay - fields = ['id', 'url', 'name'] + fields = ['id', 'url', 'device', 'name'] # diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 9edfe7bb9..ceec6747d 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -238,6 +238,11 @@ class DeviceViewSet(CustomFieldModelViewSet): """ if self.action == 'retrieve': return serializers.DeviceWithConfigContextSerializer + + request = self.get_serializer_context()['request'] + if request.query_params.get('brief', False): + return serializers.NestedDeviceSerializer + return serializers.DeviceSerializer @action(detail=True, url_path='napalm') diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index d4a42c196..c227179f4 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -44,6 +44,16 @@ class RegionTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_regions_brief(self): + + url = reverse('dcim-api:region-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_region(self): data = { @@ -158,6 +168,16 @@ class SiteTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_sites_brief(self): + + url = reverse('dcim-api:site-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_site(self): data = { @@ -262,6 +282,16 @@ class RackGroupTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_rackgroups_brief(self): + + url = reverse('dcim-api:rackgroup-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_rackgroup(self): data = { @@ -360,6 +390,16 @@ class RackRoleTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_rackroles_brief(self): + + url = reverse('dcim-api:rackrole-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_rackrole(self): data = { @@ -477,6 +517,16 @@ class RackTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_racks_brief(self): + + url = reverse('dcim-api:rack-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['display_name', 'id', 'name', 'url'] + ) + def test_create_rack(self): data = { @@ -693,6 +743,16 @@ class ManufacturerTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_manufacturers_brief(self): + + url = reverse('dcim-api:manufacturer-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_manufacturer(self): data = { @@ -792,6 +852,16 @@ class DeviceTypeTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_devicetypes_brief(self): + + url = reverse('dcim-api:devicetype-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'manufacturer', 'model', 'slug', 'url'] + ) + def test_create_devicetype(self): data = { @@ -1496,6 +1566,16 @@ class DeviceRoleTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_deviceroles_brief(self): + + url = reverse('dcim-api:devicerole-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_devicerole(self): data = { @@ -1594,6 +1674,16 @@ class PlatformTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_platforms_brief(self): + + url = reverse('dcim-api:platform-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_platform(self): data = { @@ -1722,6 +1812,16 @@ class DeviceTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_devices_brief(self): + + url = reverse('dcim-api:device-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['display_name', 'id', 'name', 'url'] + ) + def test_create_device(self): data = { @@ -1848,6 +1948,16 @@ class ConsolePortTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_consoleports_brief(self): + + url = reverse('dcim-api:consoleport-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_consoleport(self): data = { @@ -1953,6 +2063,16 @@ class ConsoleServerPortTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_consoleserverports_brief(self): + + url = reverse('dcim-api:consoleserverport-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_consoleserverport(self): data = { @@ -2054,6 +2174,16 @@ class PowerPortTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_powerports_brief(self): + + url = reverse('dcim-api:powerport-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_powerport(self): data = { @@ -2159,6 +2289,16 @@ class PowerOutletTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_poweroutlets_brief(self): + + url = reverse('dcim-api:poweroutlet-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_poweroutlet(self): data = { @@ -2285,6 +2425,16 @@ class InterfaceTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_interfaces_brief(self): + + url = reverse('dcim-api:interface-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_interface(self): data = { @@ -2456,6 +2606,16 @@ class DeviceBayTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_devicebays_brief(self): + + url = reverse('dcim-api:devicebay-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['device', 'id', 'name', 'url'] + ) + def test_create_devicebay(self): data = { @@ -2778,6 +2938,16 @@ class InterfaceConnectionTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_interfaceconnections_brief(self): + + url = reverse('dcim-api:interfaceconnection-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['connection_status', 'id', 'url'] + ) + def test_create_interfaceconnection(self): data = { @@ -2973,6 +3143,16 @@ class VirtualChassisTest(APITestCase): self.assertEqual(response.data['count'], 2) + def test_list_virtualchassis_brief(self): + + url = reverse('dcim-api:virtualchassis-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'url'] + ) + def test_create_virtualchassis(self): data = { diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 0ff87d5cf..032d96d09 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -34,6 +34,16 @@ class VRFTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_vrfs_brief(self): + + url = reverse('ipam-api:vrf-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'rd', 'url'] + ) + def test_create_vrf(self): data = { @@ -125,6 +135,16 @@ class RIRTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_rirs_brief(self): + + url = reverse('ipam-api:rir-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_rir(self): data = { @@ -218,6 +238,16 @@ class AggregateTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_aggregates_brief(self): + + url = reverse('ipam-api:aggregate-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['family', 'id', 'prefix','url'] + ) + def test_create_aggregate(self): data = { @@ -309,6 +339,16 @@ class RoleTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_roles_brief(self): + + url = reverse('ipam-api:role-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_role(self): data = { @@ -397,13 +437,23 @@ class PrefixTest(APITestCase): self.assertEqual(response.data['prefix'], str(self.prefix1.prefix)) - def test_list_prefixs(self): + def test_list_prefixes(self): url = reverse('ipam-api:prefix-list') response = self.client.get(url, **self.header) self.assertEqual(response.data['count'], 3) + def test_list_prefixes_brief(self): + + url = reverse('ipam-api:prefix-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['family', 'id', 'prefix', 'url'] + ) + def test_create_prefix(self): data = { @@ -630,6 +680,16 @@ class IPAddressTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_ipaddresses_brief(self): + + url = reverse('ipam-api:ipaddress-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['address', 'family', 'id', 'url'] + ) + def test_create_ipaddress(self): data = { @@ -718,6 +778,16 @@ class VLANGroupTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_vlangroups_brief(self): + + url = reverse('ipam-api:vlangroup-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_vlangroup(self): data = { @@ -809,6 +879,16 @@ class VLANTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_vlans_brief(self): + + url = reverse('ipam-api:vlan-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['display_name', 'id', 'name', 'url', 'vid'] + ) + def test_create_vlan(self): data = { diff --git a/netbox/secrets/tests/test_api.py b/netbox/secrets/tests/test_api.py index 985e0ea7f..d8d156ef3 100644 --- a/netbox/secrets/tests/test_api.py +++ b/netbox/secrets/tests/test_api.py @@ -73,6 +73,16 @@ class SecretRoleTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_secretroles_brief(self): + + url = reverse('secrets-api:secretrole-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_secretrole(self): data = { diff --git a/netbox/tenancy/tests/test_api.py b/netbox/tenancy/tests/test_api.py index 95e1a6de3..78b907d20 100644 --- a/netbox/tenancy/tests/test_api.py +++ b/netbox/tenancy/tests/test_api.py @@ -31,6 +31,16 @@ class TenantGroupTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_tenantgroups_brief(self): + + url = reverse('tenancy-api:tenantgroup-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_tenantgroup(self): data = { @@ -124,6 +134,16 @@ class TenantTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_tenants_brief(self): + + url = reverse('tenancy-api:tenant-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_tenant(self): data = { diff --git a/netbox/virtualization/api/serializers.py b/netbox/virtualization/api/serializers.py index 80a2f756a..b749f1e5e 100644 --- a/netbox/virtualization/api/serializers.py +++ b/netbox/virtualization/api/serializers.py @@ -169,7 +169,8 @@ class InterfaceSerializer(TaggitSerializer, ValidatedModelSerializer): class NestedInterfaceSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:interface-detail') + virtual_machine = NestedVirtualMachineSerializer(read_only=True) class Meta: model = Interface - fields = ['id', 'url', 'name'] + fields = ['id', 'url', 'virtual_machine', 'name'] diff --git a/netbox/virtualization/api/views.py b/netbox/virtualization/api/views.py index ab8ce7fbc..c3d644b8f 100644 --- a/netbox/virtualization/api/views.py +++ b/netbox/virtualization/api/views.py @@ -56,6 +56,11 @@ class VirtualMachineViewSet(CustomFieldModelViewSet): """ if self.action == 'retrieve': return serializers.VirtualMachineWithConfigContextSerializer + + request = self.get_serializer_context()['request'] + if request.query_params.get('brief', False): + return serializers.NestedVirtualMachineSerializer + return serializers.VirtualMachineSerializer @@ -65,3 +70,10 @@ class InterfaceViewSet(ModelViewSet): ).select_related('virtual_machine').prefetch_related('tags') serializer_class = serializers.InterfaceSerializer filter_class = filters.InterfaceFilter + + def get_serializer_class(self): + request = self.get_serializer_context()['request'] + if request.query_params.get('brief', False): + # Override get_serializer_for_model(), which will return the DCIM NestedInterfaceSerializer + return serializers.NestedInterfaceSerializer + return serializers.InterfaceSerializer diff --git a/netbox/virtualization/tests/test_api.py b/netbox/virtualization/tests/test_api.py index c3eebf5ed..32f56b99b 100644 --- a/netbox/virtualization/tests/test_api.py +++ b/netbox/virtualization/tests/test_api.py @@ -35,6 +35,16 @@ class ClusterTypeTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_clustertypes_brief(self): + + url = reverse('virtualization-api:clustertype-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_clustertype(self): data = { @@ -126,6 +136,16 @@ class ClusterGroupTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_clustergroups_brief(self): + + url = reverse('virtualization-api:clustergroup-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'slug', 'url'] + ) + def test_create_clustergroup(self): data = { @@ -220,6 +240,16 @@ class ClusterTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_clusters_brief(self): + + url = reverse('virtualization-api:cluster-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'url'] + ) + def test_create_cluster(self): data = { @@ -324,6 +354,16 @@ class VirtualMachineTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_virtualmachines_brief(self): + + url = reverse('virtualization-api:virtualmachine-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'url'] + ) + def test_create_virtualmachine(self): data = { @@ -447,6 +487,16 @@ class InterfaceTest(APITestCase): self.assertEqual(response.data['count'], 3) + def test_list_interfaces_brief(self): + + url = reverse('virtualization-api:interface-list') + response = self.client.get('{}?brief=1'.format(url), **self.header) + + self.assertEqual( + sorted(response.data['results'][0]), + ['id', 'name', 'url', 'virtual_machine'] + ) + def test_create_interface(self): data = {