diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index b98a7e0a5..ffae2f5de 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -22,6 +22,7 @@ When running a report or custom script, the task is now queued for background pr * [#4792](https://github.com/netbox-community/netbox/issues/4792) - Add bulk rename capability for console and power ports * [#4793](https://github.com/netbox-community/netbox/issues/4793) - Add `description` field to device component templates * [#4795](https://github.com/netbox-community/netbox/issues/4795) - Add bulk disconnect capability for console and power ports +* [#4806](https://github.com/netbox-community/netbox/issues/4806) - Add a `url` field to all API serializers * [#4807](https://github.com/netbox-community/netbox/issues/4807) - Add bulk edit ability for device bay templates * [#4817](https://github.com/netbox-community/netbox/issues/4817) - Standardize device/VM component `name` field to 64 characters @@ -50,6 +51,7 @@ When running a report or custom script, the task is now queued for background pr * An optional `description` field has been added to all device component templates * extras.Report: The `failed` field has been removed. The `completed` (boolean) and `status` (string) fields have been introduced to convey the status of a report's most recent execution. Additionally, the `result` field now conveys the nested representation of a JobResult. * extras.Script: Added `module` and `result` fields. The `result` field now conveys the nested representation of a JobResult. +* A `url` field is now included on all object representations, identifying the unique REST API URL for each object. ### Other Changes diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index e8171e2fb..10ae5e5ee 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -16,12 +16,13 @@ from .nested_serializers import * # class ProviderSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail') circuit_count = serializers.IntegerField(read_only=True) class Meta: model = Provider fields = [ - 'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags', + 'id', 'url', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', ] @@ -31,11 +32,12 @@ class ProviderSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class CircuitTypeSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail') circuit_count = serializers.IntegerField(read_only=True) class Meta: model = CircuitType - fields = ['id', 'name', 'slug', 'description', 'circuit_count'] + fields = ['id', 'url', 'name', 'slug', 'description', 'circuit_count'] class CircuitCircuitTerminationSerializer(WritableNestedSerializer): @@ -49,6 +51,7 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer): class CircuitSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail') provider = NestedProviderSerializer() status = ChoiceField(choices=CircuitStatusChoices, required=False) type = NestedCircuitTypeSerializer() @@ -59,12 +62,13 @@ class CircuitSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Circuit fields = [ - 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', + 'id', 'url', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'termination_a', 'termination_z', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] class CircuitTerminationSerializer(ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail') circuit = NestedCircuitSerializer() site = NestedSiteSerializer() cable = NestedCableSerializer(read_only=True) @@ -72,6 +76,6 @@ class CircuitTerminationSerializer(ConnectedEndpointSerializer): class Meta: model = CircuitTermination fields = [ - 'id', 'circuit', 'term_side', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', + 'id', 'url', 'circuit', 'term_side', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', ] diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 3f1eff6a4..916f86487 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -60,15 +60,17 @@ class ConnectedEndpointSerializer(ValidatedModelSerializer): # class RegionSerializer(serializers.ModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail') parent = NestedRegionSerializer(required=False, allow_null=True) site_count = serializers.IntegerField(read_only=True) class Meta: model = Region - fields = ['id', 'name', 'slug', 'parent', 'description', 'site_count'] + fields = ['id', 'url', 'name', 'slug', 'parent', 'description', 'site_count'] class SiteSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail') status = ChoiceField(choices=SiteStatusChoices, required=False) region = NestedRegionSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -83,7 +85,7 @@ class SiteSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Site fields = [ - 'id', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description', + 'id', 'url', 'name', 'slug', 'status', 'region', 'tenant', 'facility', 'asn', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'contact_name', 'contact_phone', 'contact_email', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count', 'prefix_count', 'rack_count', 'virtualmachine_count', 'vlan_count', @@ -95,24 +97,27 @@ class SiteSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class RackGroupSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail') site = NestedSiteSerializer() parent = NestedRackGroupSerializer(required=False, allow_null=True) rack_count = serializers.IntegerField(read_only=True) class Meta: model = RackGroup - fields = ['id', 'name', 'slug', 'site', 'parent', 'description', 'rack_count'] + fields = ['id', 'url', 'name', 'slug', 'site', 'parent', 'description', 'rack_count'] class RackRoleSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail') rack_count = serializers.IntegerField(read_only=True) class Meta: model = RackRole - fields = ['id', 'name', 'slug', 'color', 'description', 'rack_count'] + fields = ['id', 'url', 'name', 'slug', 'color', 'description', 'rack_count'] class RackSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail') site = NestedSiteSerializer() group = NestedRackGroupSerializer(required=False, allow_null=True, default=None) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -127,7 +132,7 @@ class RackSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Rack fields = [ - 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial', + 'id', 'url', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'status', 'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count', ] @@ -161,13 +166,14 @@ class RackUnitSerializer(serializers.Serializer): class RackReservationSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackreservation-detail') rack = NestedRackSerializer() user = NestedUserSerializer() tenant = NestedTenantSerializer(required=False, allow_null=True) class Meta: model = RackReservation - fields = ['id', 'rack', 'units', 'created', 'user', 'tenant', 'description', 'tags'] + fields = ['id', 'url', 'rack', 'units', 'created', 'user', 'tenant', 'description', 'tags'] class RackElevationDetailFilterSerializer(serializers.Serializer): @@ -211,6 +217,7 @@ class RackElevationDetailFilterSerializer(serializers.Serializer): # class ManufacturerSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail') devicetype_count = serializers.IntegerField(read_only=True) inventoryitem_count = serializers.IntegerField(read_only=True) platform_count = serializers.IntegerField(read_only=True) @@ -218,11 +225,12 @@ class ManufacturerSerializer(ValidatedModelSerializer): class Meta: model = Manufacturer fields = [ - 'id', 'name', 'slug', 'description', 'devicetype_count', 'inventoryitem_count', 'platform_count', + 'id', 'url', 'name', 'slug', 'description', 'devicetype_count', 'inventoryitem_count', 'platform_count', ] class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail') manufacturer = NestedManufacturerSerializer() subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False) device_count = serializers.IntegerField(read_only=True) @@ -230,13 +238,14 @@ class DeviceTypeSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = DeviceType fields = [ - 'id', 'manufacturer', 'model', 'slug', 'display_name', 'part_number', 'u_height', 'is_full_depth', + 'id', 'url', 'manufacturer', 'model', 'slug', 'display_name', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'front_image', 'rear_image', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', ] class ConsolePortTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleporttemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField( choices=ConsolePortTypeChoices, @@ -246,10 +255,11 @@ class ConsolePortTemplateSerializer(ValidatedModelSerializer): class Meta: model = ConsolePortTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description'] class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverporttemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField( choices=ConsolePortTypeChoices, @@ -259,10 +269,11 @@ class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer): class Meta: model = ConsoleServerPortTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description'] class PowerPortTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerporttemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField( choices=PowerPortTypeChoices, @@ -272,10 +283,11 @@ class PowerPortTemplateSerializer(ValidatedModelSerializer): class Meta: model = PowerPortTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description'] class PowerOutletTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlettemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField( choices=PowerOutletTypeChoices, @@ -293,43 +305,47 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer): class Meta: model = PowerOutletTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description'] class InterfaceTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfacetemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=InterfaceTypeChoices) class Meta: model = InterfaceTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'mgmt_only', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'mgmt_only', 'description'] class RearPortTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PortTypeChoices) class Meta: model = RearPortTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'positions', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'positions', 'description'] class FrontPortTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontporttemplate-detail') device_type = NestedDeviceTypeSerializer() type = ChoiceField(choices=PortTypeChoices) rear_port = NestedRearPortTemplateSerializer() class Meta: model = FrontPortTemplate - fields = ['id', 'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description'] class DeviceBayTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebaytemplate-detail') device_type = NestedDeviceTypeSerializer() class Meta: model = DeviceBayTemplate - fields = ['id', 'device_type', 'name', 'label', 'description'] + fields = ['id', 'url', 'device_type', 'name', 'label', 'description'] # @@ -337,17 +353,19 @@ class DeviceBayTemplateSerializer(ValidatedModelSerializer): # class DeviceRoleSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail') device_count = serializers.IntegerField(read_only=True) virtualmachine_count = serializers.IntegerField(read_only=True) class Meta: model = DeviceRole fields = [ - 'id', 'name', 'slug', 'color', 'vm_role', 'description', 'device_count', 'virtualmachine_count', + 'id', 'url', 'name', 'slug', 'color', 'vm_role', 'description', 'device_count', 'virtualmachine_count', ] class PlatformSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail') manufacturer = NestedManufacturerSerializer(required=False, allow_null=True) device_count = serializers.IntegerField(read_only=True) virtualmachine_count = serializers.IntegerField(read_only=True) @@ -355,12 +373,13 @@ class PlatformSerializer(ValidatedModelSerializer): class Meta: model = Platform fields = [ - 'id', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description', 'device_count', + 'id', 'url', 'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description', 'device_count', 'virtualmachine_count', ] class DeviceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail') device_type = NestedDeviceTypeSerializer() device_role = NestedDeviceRoleSerializer() tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -379,10 +398,10 @@ class DeviceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Device fields = [ - 'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', - 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6', - 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', + 'asset_tag', 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', + 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', + 'tags', 'custom_fields', 'created', 'last_updated', ] validators = [] @@ -415,10 +434,10 @@ class DeviceWithConfigContextSerializer(DeviceSerializer): class Meta(DeviceSerializer.Meta): fields = [ - 'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', - 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6', - 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', 'tags', - 'custom_fields', 'config_context', 'created', 'last_updated', + 'id', 'url', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', + 'asset_tag', 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', + 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data', + 'tags', 'custom_fields', 'config_context', 'created', 'last_updated', ] @swagger_serializer_method(serializer_or_field=serializers.DictField) @@ -431,6 +450,7 @@ class DeviceNAPALMSerializer(serializers.Serializer): class ConsoleServerPortSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail') device = NestedDeviceSerializer() type = ChoiceField( choices=ConsolePortTypeChoices, @@ -442,12 +462,13 @@ class ConsoleServerPortSerializer(TaggedObjectSerializer, ConnectedEndpointSeria class Meta: model = ConsoleServerPort fields = [ - 'id', 'device', 'name', 'label', 'type', 'description', 'connected_endpoint_type', 'connected_endpoint', - 'connection_status', 'cable', 'tags', + 'id', 'url', 'device', 'name', 'label', 'type', 'description', 'connected_endpoint_type', + 'connected_endpoint', 'connection_status', 'cable', 'tags', ] class ConsolePortSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail') device = NestedDeviceSerializer() type = ChoiceField( choices=ConsolePortTypeChoices, @@ -459,12 +480,13 @@ class ConsolePortSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer) class Meta: model = ConsolePort fields = [ - 'id', 'device', 'name', 'label', 'type', 'description', 'connected_endpoint_type', 'connected_endpoint', - 'connection_status', 'cable', 'tags', + 'id', 'url', 'device', 'name', 'label', 'type', 'description', 'connected_endpoint_type', + 'connected_endpoint', 'connection_status', 'cable', 'tags', ] class PowerOutletSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail') device = NestedDeviceSerializer() type = ChoiceField( choices=PowerOutletTypeChoices, @@ -486,12 +508,13 @@ class PowerOutletSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer) class Meta: model = PowerOutlet fields = [ - 'id', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'connected_endpoint_type', - 'connected_endpoint', 'connection_status', 'cable', 'tags', + 'id', 'url', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', + 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', 'tags', ] class PowerPortSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail') device = NestedDeviceSerializer() type = ChoiceField( choices=PowerPortTypeChoices, @@ -503,12 +526,13 @@ class PowerPortSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): class Meta: model = PowerPort fields = [ - 'id', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'connected_endpoint_type', - 'connected_endpoint', 'connection_status', 'cable', 'tags', + 'id', 'url', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', + 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', 'tags', ] class InterfaceSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail') device = NestedDeviceSerializer() type = ChoiceField(choices=InterfaceTypeChoices) lag = NestedInterfaceSerializer(required=False, allow_null=True) @@ -526,9 +550,9 @@ class InterfaceSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): class Meta: model = Interface fields = [ - 'id', 'device', 'name', 'label', 'type', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description', - 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', 'mode', 'untagged_vlan', - 'tagged_vlans', 'tags', 'count_ipaddresses', + 'id', 'url', 'device', 'name', 'label', 'type', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', + 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable', 'mode', + 'untagged_vlan', 'tagged_vlans', 'tags', 'count_ipaddresses', ] # TODO: This validation should be handled by Interface.clean() @@ -553,13 +577,14 @@ class InterfaceSerializer(TaggedObjectSerializer, ConnectedEndpointSerializer): class RearPortSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail') device = NestedDeviceSerializer() type = ChoiceField(choices=PortTypeChoices) cable = NestedCableSerializer(read_only=True) class Meta: model = RearPort - fields = ['id', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'tags'] + fields = ['id', 'url', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'tags'] class FrontPortRearPortSerializer(WritableNestedSerializer): @@ -574,6 +599,7 @@ class FrontPortRearPortSerializer(WritableNestedSerializer): class FrontPortSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail') device = NestedDeviceSerializer() type = ChoiceField(choices=PortTypeChoices) rear_port = FrontPortRearPortSerializer() @@ -582,17 +608,19 @@ class FrontPortSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class Meta: model = FrontPort fields = [ - 'id', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'tags', + 'id', 'url', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', + 'tags', ] class DeviceBaySerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail') device = NestedDeviceSerializer() installed_device = NestedDeviceSerializer(required=False, allow_null=True) class Meta: model = DeviceBay - fields = ['id', 'device', 'name', 'label', 'description', 'installed_device', 'tags'] + fields = ['id', 'url', 'device', 'name', 'label', 'description', 'installed_device', 'tags'] # @@ -600,6 +628,7 @@ class DeviceBaySerializer(TaggedObjectSerializer, ValidatedModelSerializer): # class InventoryItemSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail') device = NestedDeviceSerializer() # Provide a default value to satisfy UniqueTogetherValidator parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None) @@ -608,7 +637,7 @@ class InventoryItemSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class Meta: model = InventoryItem fields = [ - 'id', 'device', 'parent', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered', + 'id', 'url', 'device', 'parent', 'name', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered', 'description', 'tags', ] @@ -618,6 +647,7 @@ class InventoryItemSerializer(TaggedObjectSerializer, ValidatedModelSerializer): # class CableSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail') termination_a_type = ContentTypeField( queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS) ) @@ -632,8 +662,8 @@ class CableSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class Meta: model = Cable fields = [ - 'id', 'termination_a_type', 'termination_a_id', 'termination_a', 'termination_b_type', 'termination_b_id', - 'termination_b', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'tags', + 'id', 'url', 'termination_a_type', 'termination_a_id', 'termination_a', 'termination_b_type', + 'termination_b_id', 'termination_b', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'tags', ] def _get_termination(self, obj, side): @@ -697,12 +727,13 @@ class InterfaceConnectionSerializer(ValidatedModelSerializer): # class VirtualChassisSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail') master = NestedDeviceSerializer(required=False) member_count = serializers.IntegerField(read_only=True) class Meta: model = VirtualChassis - fields = ['id', 'name', 'domain', 'master', 'tags', 'member_count'] + fields = ['id', 'url', 'name', 'domain', 'master', 'tags', 'member_count'] # @@ -710,6 +741,7 @@ class VirtualChassisSerializer(TaggedObjectSerializer, ValidatedModelSerializer) # class PowerPanelSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail') site = NestedSiteSerializer() rack_group = NestedRackGroupSerializer( required=False, @@ -720,10 +752,11 @@ class PowerPanelSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class Meta: model = PowerPanel - fields = ['id', 'site', 'rack_group', 'name', 'tags', 'powerfeed_count'] + fields = ['id', 'url', 'site', 'rack_group', 'name', 'tags', 'powerfeed_count'] class PowerFeedSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail') power_panel = NestedPowerPanelSerializer() rack = NestedRackSerializer( required=False, @@ -750,6 +783,6 @@ class PowerFeedSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = PowerFeed fields = [ - 'id', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', + 'id', 'url', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index a466cb560..2f0235e80 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -9,7 +9,6 @@ from dcim.api.nested_serializers import ( ) from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site from extras.choices import * -from extras.constants import * from extras.models import ( ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, JobResult, Tag, ) @@ -31,13 +30,14 @@ from .nested_serializers import * # class GraphSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:graph-detail') type = ContentTypeField( queryset=ContentType.objects.filter(FeatureQuery('graphs').get_query()), ) class Meta: model = Graph - fields = ['id', 'type', 'weight', 'name', 'template_language', 'source', 'link'] + fields = ['id', 'url', 'type', 'weight', 'name', 'template_language', 'source', 'link'] class RenderedGraphSerializer(serializers.ModelSerializer): @@ -67,6 +67,7 @@ class RenderedGraphSerializer(serializers.ModelSerializer): # class ExportTemplateSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail') content_type = ContentTypeField( queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), ) @@ -78,7 +79,7 @@ class ExportTemplateSerializer(ValidatedModelSerializer): class Meta: model = ExportTemplate fields = [ - 'id', 'content_type', 'name', 'description', 'template_language', 'template_code', 'mime_type', + 'id', 'url', 'content_type', 'name', 'description', 'template_language', 'template_code', 'mime_type', 'file_extension', ] @@ -88,11 +89,12 @@ class ExportTemplateSerializer(ValidatedModelSerializer): # class TagSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:tag-detail') tagged_items = serializers.IntegerField(read_only=True) class Meta: model = Tag - fields = ['id', 'name', 'slug', 'color', 'description', 'tagged_items'] + fields = ['id', 'url', 'name', 'slug', 'color', 'description', 'tagged_items'] class TaggedObjectSerializer(serializers.Serializer): @@ -122,6 +124,7 @@ class TaggedObjectSerializer(serializers.Serializer): # class ImageAttachmentSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:imageattachment-detail') content_type = ContentTypeField( queryset=ContentType.objects.all() ) @@ -130,7 +133,8 @@ class ImageAttachmentSerializer(ValidatedModelSerializer): class Meta: model = ImageAttachment fields = [ - 'id', 'content_type', 'object_id', 'parent', 'name', 'image', 'image_height', 'image_width', 'created', + 'id', 'url', 'content_type', 'object_id', 'parent', 'name', 'image', 'image_height', 'image_width', + 'created', ] def validate(self, data): @@ -169,6 +173,7 @@ class ImageAttachmentSerializer(ValidatedModelSerializer): # class ConfigContextSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail') regions = SerializedPKRelatedField( queryset=Region.objects.all(), serializer=NestedRegionSerializer, @@ -227,7 +232,7 @@ class ConfigContextSerializer(ValidatedModelSerializer): class Meta: model = ConfigContext fields = [ - 'id', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', + 'id', 'url', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data', ] @@ -258,6 +263,11 @@ class JobResultSerializer(serializers.ModelSerializer): # class ReportSerializer(serializers.Serializer): + url = serializers.HyperlinkedIdentityField( + view_name='extras-api:report-detail', + lookup_field='full_name', + lookup_url_kwarg='pk' + ) id = serializers.CharField(read_only=True, source="full_name") module = serializers.CharField(max_length=255) name = serializers.CharField(max_length=255) @@ -275,6 +285,11 @@ class ReportDetailSerializer(ReportSerializer): # class ScriptSerializer(serializers.Serializer): + url = serializers.HyperlinkedIdentityField( + view_name='extras-api:script-detail', + lookup_field='full_name', + lookup_url_kwarg='pk' + ) id = serializers.CharField(read_only=True, source="full_name") module = serializers.CharField(max_length=255) name = serializers.CharField(read_only=True) @@ -318,6 +333,7 @@ class ScriptOutputSerializer(serializers.Serializer): # class ObjectChangeSerializer(serializers.ModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='extras-api:objectchange-detail') user = NestedUserSerializer( read_only=True ) @@ -335,8 +351,8 @@ class ObjectChangeSerializer(serializers.ModelSerializer): class Meta: model = ObjectChange fields = [ - 'id', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id', - 'changed_object', 'object_data', + 'id', 'url', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', + 'changed_object_id', 'changed_object', 'object_data', ] @swagger_serializer_method(serializer_or_field=serializers.DictField) diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index d7f70f113..a98681d34 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -27,6 +27,7 @@ from .nested_serializers import * # class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail') tenant = NestedTenantSerializer(required=False, allow_null=True) ipaddress_count = serializers.IntegerField(read_only=True) prefix_count = serializers.IntegerField(read_only=True) @@ -34,8 +35,8 @@ class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = VRF fields = [ - 'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name', 'custom_fields', - 'created', 'last_updated', 'ipaddress_count', 'prefix_count', + 'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name', + 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count', ] @@ -44,21 +45,23 @@ class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class RIRSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail') aggregate_count = serializers.IntegerField(read_only=True) class Meta: model = RIR - fields = ['id', 'name', 'slug', 'is_private', 'description', 'aggregate_count'] + fields = ['id', 'url', 'name', 'slug', 'is_private', 'description', 'aggregate_count'] class AggregateSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail') family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) rir = NestedRIRSerializer() class Meta: model = Aggregate fields = [ - 'id', 'family', 'prefix', 'rir', 'date_added', 'description', 'tags', 'custom_fields', 'created', + 'id', 'url', 'family', 'prefix', 'rir', 'date_added', 'description', 'tags', 'custom_fields', 'created', 'last_updated', ] read_only_fields = ['family'] @@ -69,21 +72,23 @@ class AggregateSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class RoleSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail') prefix_count = serializers.IntegerField(read_only=True) vlan_count = serializers.IntegerField(read_only=True) class Meta: model = Role - fields = ['id', 'name', 'slug', 'weight', 'description', 'prefix_count', 'vlan_count'] + fields = ['id', 'url', 'name', 'slug', 'weight', 'description', 'prefix_count', 'vlan_count'] class VLANGroupSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlangroup-detail') site = NestedSiteSerializer(required=False, allow_null=True) vlan_count = serializers.IntegerField(read_only=True) class Meta: model = VLANGroup - fields = ['id', 'name', 'slug', 'site', 'description', 'vlan_count'] + fields = ['id', 'url', 'name', 'slug', 'site', 'description', 'vlan_count'] validators = [] def validate(self, data): @@ -101,6 +106,7 @@ class VLANGroupSerializer(ValidatedModelSerializer): class VLANSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail') site = NestedSiteSerializer(required=False, allow_null=True) group = NestedVLANGroupSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -111,8 +117,8 @@ class VLANSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = VLAN fields = [ - 'id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'tags', 'display_name', - 'custom_fields', 'created', 'last_updated', 'prefix_count', + 'id', 'url', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'tags', + 'display_name', 'custom_fields', 'created', 'last_updated', 'prefix_count', ] validators = [] @@ -135,6 +141,7 @@ class VLANSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class PrefixSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:prefix-detail') family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) site = NestedSiteSerializer(required=False, allow_null=True) vrf = NestedVRFSerializer(required=False, allow_null=True) @@ -146,8 +153,8 @@ class PrefixSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Prefix fields = [ - 'id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description', - 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', + 'description', 'tags', 'custom_fields', 'created', 'last_updated', ] read_only_fields = ['family'] @@ -227,6 +234,7 @@ class IPAddressInterfaceSerializer(WritableNestedSerializer): class IPAddressSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail') family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) vrf = NestedVRFSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -243,9 +251,9 @@ class IPAddressSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = IPAddress fields = [ - 'id', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'assigned_object_type', 'assigned_object_id', - 'assigned_object', 'nat_inside', 'nat_outside', 'dns_name', 'description', 'tags', 'custom_fields', - 'created', 'last_updated', + 'id', 'url', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'assigned_object_type', + 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside', 'dns_name', 'description', 'tags', + 'custom_fields', 'created', 'last_updated', ] read_only_fields = ['family'] @@ -283,6 +291,7 @@ class AvailableIPSerializer(serializers.Serializer): # class ServiceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='ipam-api:service-detail') device = NestedDeviceSerializer(required=False, allow_null=True) virtual_machine = NestedVirtualMachineSerializer(required=False, allow_null=True) protocol = ChoiceField(choices=ServiceProtocolChoices, required=False) @@ -296,6 +305,6 @@ class ServiceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Service fields = [ - 'id', 'device', 'virtual_machine', 'name', 'port', 'protocol', 'ipaddresses', 'description', 'tags', + 'id', 'url', 'device', 'virtual_machine', 'name', 'port', 'protocol', 'ipaddresses', 'description', 'tags', 'custom_fields', 'created', 'last_updated', ] diff --git a/netbox/secrets/api/serializers.py b/netbox/secrets/api/serializers.py index 54132dd34..2862259d8 100644 --- a/netbox/secrets/api/serializers.py +++ b/netbox/secrets/api/serializers.py @@ -13,14 +13,16 @@ from .nested_serializers import * # class SecretRoleSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='secrets-api:secretrole-detail') secret_count = serializers.IntegerField(read_only=True) class Meta: model = SecretRole - fields = ['id', 'name', 'slug', 'description', 'secret_count'] + fields = ['id', 'url', 'name', 'slug', 'description', 'secret_count'] class SecretSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='secrets-api:secret-detail') device = NestedDeviceSerializer() role = NestedSecretRoleSerializer() plaintext = serializers.CharField() @@ -28,7 +30,8 @@ class SecretSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Secret fields = [ - 'id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'custom_fields', 'created', + 'last_updated', ] validators = [] diff --git a/netbox/tenancy/api/serializers.py b/netbox/tenancy/api/serializers.py index 4454ac776..4589878e6 100644 --- a/netbox/tenancy/api/serializers.py +++ b/netbox/tenancy/api/serializers.py @@ -12,15 +12,17 @@ from .nested_serializers import * # class TenantGroupSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail') parent = NestedTenantGroupSerializer(required=False, allow_null=True) tenant_count = serializers.IntegerField(read_only=True) class Meta: model = TenantGroup - fields = ['id', 'name', 'slug', 'parent', 'description', 'tenant_count'] + fields = ['id', 'url', 'name', 'slug', 'parent', 'description', 'tenant_count'] class TenantSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail') group = NestedTenantGroupSerializer(required=False) circuit_count = serializers.IntegerField(read_only=True) device_count = serializers.IntegerField(read_only=True) @@ -36,7 +38,7 @@ class TenantSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Tenant fields = [ - 'id', 'name', 'slug', 'group', 'description', 'comments', 'tags', 'custom_fields', 'created', + 'id', 'url', 'name', 'slug', 'group', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count', 'ipaddress_count', 'prefix_count', 'rack_count', 'site_count', 'virtualmachine_count', 'vlan_count', 'vrf_count', 'cluster_count', ] diff --git a/netbox/virtualization/api/serializers.py b/netbox/virtualization/api/serializers.py index 5698791f8..711e1359e 100644 --- a/netbox/virtualization/api/serializers.py +++ b/netbox/virtualization/api/serializers.py @@ -19,22 +19,25 @@ from .nested_serializers import * # class ClusterTypeSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail') cluster_count = serializers.IntegerField(read_only=True) class Meta: model = ClusterType - fields = ['id', 'name', 'slug', 'description', 'cluster_count'] + fields = ['id', 'url', 'name', 'slug', 'description', 'cluster_count'] class ClusterGroupSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail') cluster_count = serializers.IntegerField(read_only=True) class Meta: model = ClusterGroup - fields = ['id', 'name', 'slug', 'description', 'cluster_count'] + fields = ['id', 'url', 'name', 'slug', 'description', 'cluster_count'] class ClusterSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail') type = NestedClusterTypeSerializer() group = NestedClusterGroupSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True) @@ -45,8 +48,8 @@ class ClusterSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): class Meta: model = Cluster fields = [ - 'id', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', - 'device_count', 'virtualmachine_count', + 'id', 'url', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', 'custom_fields', 'created', + 'last_updated', 'device_count', 'virtualmachine_count', ] @@ -55,6 +58,7 @@ class ClusterSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): # class VirtualMachineSerializer(TaggedObjectSerializer, CustomFieldModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail') status = ChoiceField(choices=VirtualMachineStatusChoices, required=False) site = NestedSiteSerializer(read_only=True) cluster = NestedClusterSerializer() @@ -68,7 +72,7 @@ class VirtualMachineSerializer(TaggedObjectSerializer, CustomFieldModelSerialize class Meta: model = VirtualMachine fields = [ - 'id', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', + 'id', 'url', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', ] @@ -80,7 +84,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer): class Meta(VirtualMachineSerializer.Meta): fields = [ - 'id', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', + 'id', 'url', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated', ] @@ -95,6 +99,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer): # class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail') virtual_machine = NestedVirtualMachineSerializer() mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False) untagged_vlan = NestedVLANSerializer(required=False, allow_null=True) @@ -108,6 +113,6 @@ class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class Meta: model = VMInterface fields = [ - 'id', 'virtual_machine', 'name', 'enabled', 'mtu', 'mac_address', 'description', 'mode', 'untagged_vlan', - 'tagged_vlans', 'tags', + 'id', 'url', 'virtual_machine', 'name', 'enabled', 'mtu', 'mac_address', 'description', 'mode', + 'untagged_vlan', 'tagged_vlans', 'tags', ]