Bläddra i källkod

15156 Add display_url to REST API (#16412)

* 15156 add display_url to REST API

* 15156 fix view name

* 15156 fix typo

* 15156 fix tests

* 15156 add url display_url to base class

* 15156 add url display_url to base class

* 15156 add url display_url to base class

* 15156 review changes

* 15156 review changes

* 15156 review changes

* 15156 review changes

* 15156 remove bogus code

* 15156 remove bogus code

* 15156 review changes

* 15156 review changes

* 15156 review changes

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Arthur Hanson 1 år sedan
förälder
incheckning
52546608f6
62 ändrade filer med 436 tillägg och 620 borttagningar
  1. 3 7
      docs/plugins/development/rest-api.md
  2. 6 12
      netbox/circuits/api/nested_serializers.py
  3. 10 14
      netbox/circuits/api/serializers_/circuits.py
  4. 5 8
      netbox/circuits/api/serializers_/providers.py
  5. 3 6
      netbox/core/api/nested_serializers.py
  6. 2 3
      netbox/core/api/serializers_/change_logging.py
  7. 2 8
      netbox/core/api/serializers_/data.py
  8. 1 2
      netbox/core/api/serializers_/jobs.py
  9. 42 84
      netbox/dcim/api/nested_serializers.py
  10. 8 10
      netbox/dcim/api/serializers_/cables.py
  11. 23 34
      netbox/dcim/api/serializers_/device_components.py
  12. 19 22
      netbox/dcim/api/serializers_/devices.py
  13. 23 29
      netbox/dcim/api/serializers_/devicetype_components.py
  14. 9 11
      netbox/dcim/api/serializers_/devicetypes.py
  15. 2 3
      netbox/dcim/api/serializers_/manufacturers.py
  16. 2 3
      netbox/dcim/api/serializers_/platforms.py
  17. 6 8
      netbox/dcim/api/serializers_/power.py
  18. 8 11
      netbox/dcim/api/serializers_/racks.py
  19. 4 6
      netbox/dcim/api/serializers_/roles.py
  20. 10 14
      netbox/dcim/api/serializers_/sites.py
  21. 2 3
      netbox/dcim/api/serializers_/virtualchassis.py
  22. 16 23
      netbox/extras/api/nested_serializers.py
  23. 2 3
      netbox/extras/api/serializers_/attachments.py
  24. 0 1
      netbox/extras/api/serializers_/bookmarks.py
  25. 4 5
      netbox/extras/api/serializers_/configcontexts.py
  26. 2 3
      netbox/extras/api/serializers_/configtemplates.py
  27. 6 8
      netbox/extras/api/serializers_/customfields.py
  28. 2 3
      netbox/extras/api/serializers_/customlinks.py
  29. 4 6
      netbox/extras/api/serializers_/events.py
  30. 1 2
      netbox/extras/api/serializers_/exporttemplates.py
  31. 2 3
      netbox/extras/api/serializers_/journaling.py
  32. 2 3
      netbox/extras/api/serializers_/savedfilters.py
  33. 1 2
      netbox/extras/api/serializers_/scripts.py
  34. 2 3
      netbox/extras/api/serializers_/tags.py
  35. 16 32
      netbox/ipam/api/nested_serializers.py
  36. 6 9
      netbox/ipam/api/serializers_/asns.py
  37. 4 6
      netbox/ipam/api/serializers_/fhrpgroups.py
  38. 10 14
      netbox/ipam/api/serializers_/ip.py
  39. 2 3
      netbox/ipam/api/serializers_/roles.py
  40. 4 6
      netbox/ipam/api/serializers_/services.py
  41. 5 6
      netbox/ipam/api/serializers_/vlans.py
  42. 3 5
      netbox/ipam/api/serializers_/vrfs.py
  43. 3 0
      netbox/netbox/api/serializers/base.py
  44. 53 0
      netbox/netbox/api/serializers/fields.py
  45. 1 2
      netbox/netbox/api/serializers/nested.py
  46. 5 11
      netbox/tenancy/api/nested_serializers.py
  47. 8 11
      netbox/tenancy/api/serializers_/contacts.py
  48. 6 7
      netbox/tenancy/api/serializers_/tenants.py
  49. 6 8
      netbox/users/api/nested_serializers.py
  50. 2 3
      netbox/users/api/serializers_/permissions.py
  51. 4 5
      netbox/users/api/serializers_/tokens.py
  52. 3 5
      netbox/users/api/serializers_/users.py
  53. 6 12
      netbox/virtualization/api/nested_serializers.py
  54. 7 9
      netbox/virtualization/api/serializers_/clusters.py
  55. 7 10
      netbox/virtualization/api/serializers_/virtualmachines.py
  56. 10 34
      netbox/vpn/api/nested_serializers.py
  57. 10 25
      netbox/vpn/api/serializers_/crypto.py
  58. 3 5
      netbox/vpn/api/serializers_/l2vpn.py
  59. 7 13
      netbox/vpn/api/serializers_/tunnels.py
  60. 3 6
      netbox/wireless/api/nested_serializers.py
  61. 5 6
      netbox/wireless/api/serializers_/wirelesslans.py
  62. 3 4
      netbox/wireless/api/serializers_/wirelesslinks.py

+ 3 - 7
docs/plugins/development/rest-api.md

@@ -27,7 +27,7 @@ Serializers are responsible for converting Python objects to JSON data suitable
 
 
 #### Example
 #### Example
 
 
-To create a serializer for a plugin model, subclass `NetBoxModelSerializer` in `api/serializers.py`. Specify the model class and the fields to include within the serializer's `Meta` class. It is generally advisable to include a `url` attribute on each serializer. This will render the direct link to access the object being rendered.
+To create a serializer for a plugin model, subclass `NetBoxModelSerializer` in `api/serializers.py`. Specify the model class and the fields to include within the serializer's `Meta` class.
 
 
 ```python
 ```python
 # api/serializers.py
 # api/serializers.py
@@ -36,9 +36,7 @@ from netbox.api.serializers import NetBoxModelSerializer
 from my_plugin.models import MyModel
 from my_plugin.models import MyModel
 
 
 class MyModelSerializer(NetBoxModelSerializer):
 class MyModelSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='plugins-api:myplugin-api:mymodel-detail'
-    )
+    foo = SiteSerializer(nested=True, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = MyModel
         model = MyModel
@@ -63,9 +61,7 @@ from netbox.api.serializers import WritableNestedSerializer
 from my_plugin.models import MyModel
 from my_plugin.models import MyModel
 
 
 class NestedMyModelSerializer(WritableNestedSerializer):
 class NestedMyModelSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='plugins-api:myplugin-api:mymodel-detail'
-    )
+    foo = SiteSerializer(nested=True, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = MyModel
         model = MyModel

+ 6 - 12
netbox/circuits/api/nested_serializers.py

@@ -20,11 +20,10 @@ __all__ = [
 #
 #
 
 
 class NestedProviderNetworkSerializer(WritableNestedSerializer):
 class NestedProviderNetworkSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
 
 
     class Meta:
     class Meta:
         model = ProviderNetwork
         model = ProviderNetwork
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 #
 #
@@ -35,12 +34,11 @@ class NestedProviderNetworkSerializer(WritableNestedSerializer):
     exclude_fields=('circuit_count',),
     exclude_fields=('circuit_count',),
 )
 )
 class NestedProviderSerializer(WritableNestedSerializer):
 class NestedProviderSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail')
     circuit_count = RelatedObjectCountField('circuits')
     circuit_count = RelatedObjectCountField('circuits')
 
 
     class Meta:
     class Meta:
         model = Provider
         model = Provider
-        fields = ['id', 'url', 'display', 'name', 'slug', 'circuit_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'circuit_count']
 
 
 
 
 #
 #
@@ -48,11 +46,10 @@ class NestedProviderSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedProviderAccountSerializer(WritableNestedSerializer):
 class NestedProviderAccountSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provideraccount-detail')
 
 
     class Meta:
     class Meta:
         model = ProviderAccount
         model = ProviderAccount
-        fields = ['id', 'url', 'display', 'name', 'account']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'account']
 
 
 
 
 #
 #
@@ -63,26 +60,23 @@ class NestedProviderAccountSerializer(WritableNestedSerializer):
     exclude_fields=('circuit_count',),
     exclude_fields=('circuit_count',),
 )
 )
 class NestedCircuitTypeSerializer(WritableNestedSerializer):
 class NestedCircuitTypeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail')
     circuit_count = RelatedObjectCountField('circuits')
     circuit_count = RelatedObjectCountField('circuits')
 
 
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
-        fields = ['id', 'url', 'display', 'name', 'slug', 'circuit_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'circuit_count']
 
 
 
 
 class NestedCircuitSerializer(WritableNestedSerializer):
 class NestedCircuitSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
 
 
     class Meta:
     class Meta:
         model = Circuit
         model = Circuit
-        fields = ['id', 'url', 'display', 'cid']
+        fields = ['id', 'url', 'display_url', 'display', 'cid']
 
 
 
 
 class NestedCircuitTerminationSerializer(WritableNestedSerializer):
 class NestedCircuitTerminationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
     circuit = NestedCircuitSerializer()
     circuit = NestedCircuitSerializer()
 
 
     class Meta:
     class Meta:
         model = CircuitTermination
         model = CircuitTermination
-        fields = ['id', 'url', 'display', 'circuit', 'term_side', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'cable', '_occupied']

+ 10 - 14
netbox/circuits/api/serializers_/circuits.py

@@ -18,7 +18,6 @@ __all__ = (
 
 
 
 
 class CircuitTypeSerializer(NetBoxModelSerializer):
 class CircuitTypeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittype-detail')
 
 
     # Related object counts
     # Related object counts
     circuit_count = RelatedObjectCountField('circuits')
     circuit_count = RelatedObjectCountField('circuits')
@@ -26,27 +25,25 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'circuit_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'circuit_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
 
 
 
 
 class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
 class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
     site = SiteSerializer(nested=True, allow_null=True)
     site = SiteSerializer(nested=True, allow_null=True)
     provider_network = ProviderNetworkSerializer(nested=True, allow_null=True)
     provider_network = ProviderNetworkSerializer(nested=True, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = CircuitTermination
         model = CircuitTermination
         fields = [
         fields = [
-            'id', 'url', 'display', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id',
-            'description',
+            'id', 'url', 'display_url', 'display', 'site', 'provider_network', 'port_speed', 'upstream_speed',
+            'xconnect_id', 'description',
         ]
         ]
 
 
 
 
 class CircuitSerializer(NetBoxModelSerializer):
 class CircuitSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuit-detail')
     provider = ProviderSerializer(nested=True)
     provider = ProviderSerializer(nested=True)
     provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
     provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
     status = ChoiceField(choices=CircuitStatusChoices, required=False)
     status = ChoiceField(choices=CircuitStatusChoices, required=False)
@@ -58,15 +55,14 @@ class CircuitSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Circuit
         model = Circuit
         fields = [
         fields = [
-            'id', 'url', 'display', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'install_date',
-            'termination_date', 'commit_rate', 'description', 'termination_a', 'termination_z', 'comments', 'tags',
-            'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant',
+            'install_date', 'termination_date', 'commit_rate', 'description', 'termination_a', 'termination_z',
+            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'cid', 'description')
         brief_fields = ('id', 'url', 'display', 'cid', 'description')
 
 
 
 
 class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer):
 class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
     circuit = CircuitSerializer(nested=True)
     circuit = CircuitSerializer(nested=True)
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     provider_network = ProviderNetworkSerializer(nested=True, required=False, allow_null=True)
     provider_network = ProviderNetworkSerializer(nested=True, required=False, allow_null=True)
@@ -74,8 +70,8 @@ class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer
     class Meta:
     class Meta:
         model = CircuitTermination
         model = CircuitTermination
         fields = [
         fields = [
-            'id', 'url', 'display', 'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed',
-            'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers',
-            'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
+            'id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'site', 'provider_network', 'port_speed',
+            'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_end',
+            'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'circuit', 'term_side', 'description', 'cable', '_occupied')
         brief_fields = ('id', 'url', 'display', 'circuit', 'term_side', 'description', 'cable', '_occupied')

+ 5 - 8
netbox/circuits/api/serializers_/providers.py

@@ -15,7 +15,6 @@ __all__ = (
 
 
 
 
 class ProviderSerializer(NetBoxModelSerializer):
 class ProviderSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provider-detail')
     accounts = SerializedPKRelatedField(
     accounts = SerializedPKRelatedField(
         queryset=ProviderAccount.objects.all(),
         queryset=ProviderAccount.objects.all(),
         serializer=NestedProviderAccountSerializer,
         serializer=NestedProviderAccountSerializer,
@@ -36,34 +35,32 @@ class ProviderSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Provider
         model = Provider
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'accounts', 'description', 'comments', 'asns', 'tags',
-            'custom_fields', 'created', 'last_updated', 'circuit_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'accounts', 'description', 'comments',
+            'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
 
 
 
 
 class ProviderAccountSerializer(NetBoxModelSerializer):
 class ProviderAccountSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:provideraccount-detail')
     provider = ProviderSerializer(nested=True)
     provider = ProviderSerializer(nested=True)
     name = serializers.CharField(allow_blank=True, max_length=100, required=False, default='')
     name = serializers.CharField(allow_blank=True, max_length=100, required=False, default='')
 
 
     class Meta:
     class Meta:
         model = ProviderAccount
         model = ProviderAccount
         fields = [
         fields = [
-            'id', 'url', 'display', 'provider', 'name', 'account', 'description', 'comments', 'tags', 'custom_fields',
-            'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'provider', 'name', 'account', 'description', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'account', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'account', 'description')
 
 
 
 
 class ProviderNetworkSerializer(NetBoxModelSerializer):
 class ProviderNetworkSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
     provider = ProviderSerializer(nested=True)
     provider = ProviderSerializer(nested=True)
 
 
     class Meta:
     class Meta:
         model = ProviderNetwork
         model = ProviderNetwork
         fields = [
         fields = [
-            'id', 'url', 'display', 'provider', 'name', 'service_id', 'description', 'comments', 'tags',
+            'id', 'url', 'display_url', 'display', 'provider', 'name', 'service_id', 'description', 'comments', 'tags',
             'custom_fields', 'created', 'last_updated',
             'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 3 - 6
netbox/core/api/nested_serializers.py

@@ -14,23 +14,20 @@ __all__ = (
 
 
 
 
 class NestedDataSourceSerializer(WritableNestedSerializer):
 class NestedDataSourceSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='core-api:datasource-detail')
 
 
     class Meta:
     class Meta:
         model = DataSource
         model = DataSource
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedDataFileSerializer(WritableNestedSerializer):
 class NestedDataFileSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='core-api:datafile-detail')
 
 
     class Meta:
     class Meta:
         model = DataFile
         model = DataFile
-        fields = ['id', 'url', 'display', 'path']
+        fields = ['id', 'url', 'display_url', 'display', 'path']
 
 
 
 
 class NestedJobSerializer(serializers.ModelSerializer):
 class NestedJobSerializer(serializers.ModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
     status = ChoiceField(choices=JobStatusChoices)
     status = ChoiceField(choices=JobStatusChoices)
     user = UserSerializer(
     user = UserSerializer(
         nested=True,
         nested=True,
@@ -39,4 +36,4 @@ class NestedJobSerializer(serializers.ModelSerializer):
 
 
     class Meta:
     class Meta:
         model = Job
         model = Job
-        fields = ['url', 'created', 'completed', 'user', 'status']
+        fields = ['url', 'display_url', 'created', 'completed', 'user', 'status']

+ 2 - 3
netbox/core/api/serializers_/change_logging.py

@@ -15,7 +15,6 @@ __all__ = (
 
 
 
 
 class ObjectChangeSerializer(BaseModelSerializer):
 class ObjectChangeSerializer(BaseModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='core-api:objectchange-detail')
     user = UserSerializer(
     user = UserSerializer(
         nested=True,
         nested=True,
         read_only=True
         read_only=True
@@ -44,8 +43,8 @@ class ObjectChangeSerializer(BaseModelSerializer):
     class Meta:
     class Meta:
         model = ObjectChange
         model = ObjectChange
         fields = [
         fields = [
-            'id', 'url', 'display', 'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type',
-            'changed_object_id', 'changed_object', 'prechange_data', 'postchange_data',
+            'id', 'url', 'display_url', 'display', 'time', 'user', 'user_name', 'request_id', 'action',
+            'changed_object_type', 'changed_object_id', 'changed_object', 'prechange_data', 'postchange_data',
         ]
         ]
 
 
     @extend_schema_field(serializers.JSONField(allow_null=True))
     @extend_schema_field(serializers.JSONField(allow_null=True))

+ 2 - 8
netbox/core/api/serializers_/data.py

@@ -13,9 +13,6 @@ __all__ = (
 
 
 
 
 class DataSourceSerializer(NetBoxModelSerializer):
 class DataSourceSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='core-api:datasource-detail'
-    )
     type = ChoiceField(
     type = ChoiceField(
         choices=get_data_backend_choices()
         choices=get_data_backend_choices()
     )
     )
@@ -30,16 +27,13 @@ class DataSourceSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = DataSource
         model = DataSource
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', 'comments',
+            'id', 'url', 'display_url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', 'comments',
             'parameters', 'ignore_rules', 'custom_fields', 'created', 'last_updated', 'file_count',
             'parameters', 'ignore_rules', 'custom_fields', 'created', 'last_updated', 'file_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class DataFileSerializer(NetBoxModelSerializer):
 class DataFileSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='core-api:datafile-detail'
-    )
     source = DataSourceSerializer(
     source = DataSourceSerializer(
         nested=True,
         nested=True,
         read_only=True
         read_only=True
@@ -48,6 +42,6 @@ class DataFileSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = DataFile
         model = DataFile
         fields = [
         fields = [
-            'id', 'url', 'display', 'source', 'path', 'last_updated', 'size', 'hash',
+            'id', 'url', 'display_url', 'display', 'source', 'path', 'last_updated', 'size', 'hash',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'path')
         brief_fields = ('id', 'url', 'display', 'path')

+ 1 - 2
netbox/core/api/serializers_/jobs.py

@@ -12,7 +12,6 @@ __all__ = (
 
 
 
 
 class JobSerializer(BaseModelSerializer):
 class JobSerializer(BaseModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='core-api:job-detail')
     user = UserSerializer(
     user = UserSerializer(
         nested=True,
         nested=True,
         read_only=True
         read_only=True
@@ -25,7 +24,7 @@ class JobSerializer(BaseModelSerializer):
     class Meta:
     class Meta:
         model = Job
         model = Job
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', 'interval',
+            'id', 'url', 'display_url', 'display', 'object_type', 'object_id', 'name', 'status', 'created', 'scheduled', 'interval',
             'started', 'completed', 'user', 'data', 'error', 'job_id',
             'started', 'completed', 'user', 'data', 'error', 'job_id',
         ]
         ]
         brief_fields = ('url', 'created', 'completed', 'user', 'status')
         brief_fields = ('url', 'created', 'completed', 'user', 'status')

+ 42 - 84
netbox/dcim/api/nested_serializers.py

@@ -57,34 +57,31 @@ __all__ = [
     exclude_fields=('site_count',),
     exclude_fields=('site_count',),
 )
 )
 class NestedRegionSerializer(WritableNestedSerializer):
 class NestedRegionSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
     site_count = serializers.IntegerField(read_only=True)
     site_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Region
         model = models.Region
-        fields = ['id', 'url', 'display', 'name', 'slug', 'site_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('site_count',),
     exclude_fields=('site_count',),
 )
 )
 class NestedSiteGroupSerializer(WritableNestedSerializer):
 class NestedSiteGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:sitegroup-detail')
     site_count = serializers.IntegerField(read_only=True)
     site_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.SiteGroup
         model = models.SiteGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'site_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'site_count', '_depth']
 
 
 
 
 class NestedSiteSerializer(WritableNestedSerializer):
 class NestedSiteSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
 
 
     class Meta:
     class Meta:
         model = models.Site
         model = models.Site
-        fields = ['id', 'url', 'display', 'name', 'slug']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug']
 
 
 
 
 #
 #
@@ -95,46 +92,42 @@ class NestedSiteSerializer(WritableNestedSerializer):
     exclude_fields=('rack_count',),
     exclude_fields=('rack_count',),
 )
 )
 class NestedLocationSerializer(WritableNestedSerializer):
 class NestedLocationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
     rack_count = serializers.IntegerField(read_only=True)
     rack_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Location
         model = models.Location
-        fields = ['id', 'url', 'display', 'name', 'slug', 'rack_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count', '_depth']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('rack_count',),
     exclude_fields=('rack_count',),
 )
 )
 class NestedRackRoleSerializer(WritableNestedSerializer):
 class NestedRackRoleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
     rack_count = RelatedObjectCountField('racks')
     rack_count = RelatedObjectCountField('racks')
 
 
     class Meta:
     class Meta:
         model = models.RackRole
         model = models.RackRole
-        fields = ['id', 'url', 'display', 'name', 'slug', 'rack_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'rack_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('device_count',),
     exclude_fields=('device_count',),
 )
 )
 class NestedRackSerializer(WritableNestedSerializer):
 class NestedRackSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
     device_count = RelatedObjectCountField('devices')
     device_count = RelatedObjectCountField('devices')
 
 
     class Meta:
     class Meta:
         model = models.Rack
         model = models.Rack
-        fields = ['id', 'url', 'display', 'name', 'device_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'device_count']
 
 
 
 
 class NestedRackReservationSerializer(WritableNestedSerializer):
 class NestedRackReservationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackreservation-detail')
     user = serializers.SerializerMethodField(read_only=True)
     user = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.RackReservation
         model = models.RackReservation
-        fields = ['id', 'url', 'display', 'user', 'units']
+        fields = ['id', 'url', 'display_url', 'display', 'user', 'units']
 
 
     def get_user(self, obj):
     def get_user(self, obj):
         return obj.user.username
         return obj.user.username
@@ -148,34 +141,31 @@ class NestedRackReservationSerializer(WritableNestedSerializer):
     exclude_fields=('devicetype_count',),
     exclude_fields=('devicetype_count',),
 )
 )
 class NestedManufacturerSerializer(WritableNestedSerializer):
 class NestedManufacturerSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
     devicetype_count = RelatedObjectCountField('device_types')
     devicetype_count = RelatedObjectCountField('device_types')
 
 
     class Meta:
     class Meta:
         model = models.Manufacturer
         model = models.Manufacturer
-        fields = ['id', 'url', 'display', 'name', 'slug', 'devicetype_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'devicetype_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('device_count',),
     exclude_fields=('device_count',),
 )
 )
 class NestedDeviceTypeSerializer(WritableNestedSerializer):
 class NestedDeviceTypeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
     manufacturer = NestedManufacturerSerializer(read_only=True)
     manufacturer = NestedManufacturerSerializer(read_only=True)
     device_count = RelatedObjectCountField('instances')
     device_count = RelatedObjectCountField('instances')
 
 
     class Meta:
     class Meta:
         model = models.DeviceType
         model = models.DeviceType
-        fields = ['id', 'url', 'display', 'manufacturer', 'model', 'slug', 'device_count']
+        fields = ['id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'device_count']
 
 
 
 
 class NestedModuleTypeSerializer(WritableNestedSerializer):
 class NestedModuleTypeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
     manufacturer = NestedManufacturerSerializer(read_only=True)
     manufacturer = NestedManufacturerSerializer(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.ModuleType
         model = models.ModuleType
-        fields = ['id', 'url', 'display', 'manufacturer', 'model']
+        fields = ['id', 'url', 'display_url', 'display', 'manufacturer', 'model']
 
 
 
 
 #
 #
@@ -183,84 +173,74 @@ class NestedModuleTypeSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedConsolePortTemplateSerializer(WritableNestedSerializer):
 class NestedConsolePortTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ConsolePortTemplate
         model = models.ConsolePortTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedConsoleServerPortTemplateSerializer(WritableNestedSerializer):
 class NestedConsoleServerPortTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ConsoleServerPortTemplate
         model = models.ConsoleServerPortTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedPowerPortTemplateSerializer(WritableNestedSerializer):
 class NestedPowerPortTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.PowerPortTemplate
         model = models.PowerPortTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedPowerOutletTemplateSerializer(WritableNestedSerializer):
 class NestedPowerOutletTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlettemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.PowerOutletTemplate
         model = models.PowerOutletTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedInterfaceTemplateSerializer(WritableNestedSerializer):
 class NestedInterfaceTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfacetemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.InterfaceTemplate
         model = models.InterfaceTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedRearPortTemplateSerializer(WritableNestedSerializer):
 class NestedRearPortTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.RearPortTemplate
         model = models.RearPortTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedFrontPortTemplateSerializer(WritableNestedSerializer):
 class NestedFrontPortTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.FrontPortTemplate
         model = models.FrontPortTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedModuleBayTemplateSerializer(WritableNestedSerializer):
 class NestedModuleBayTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebaytemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ModuleBayTemplate
         model = models.ModuleBayTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedDeviceBayTemplateSerializer(WritableNestedSerializer):
 class NestedDeviceBayTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebaytemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.DeviceBayTemplate
         model = models.DeviceBayTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
 class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemtemplate-detail')
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.InventoryItemTemplate
         model = models.InventoryItemTemplate
-        fields = ['id', 'url', 'display', 'name', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', '_depth']
 
 
 
 
 #
 #
@@ -271,171 +251,154 @@ class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
     exclude_fields=('device_count', 'virtualmachine_count'),
     exclude_fields=('device_count', 'virtualmachine_count'),
 )
 )
 class NestedDeviceRoleSerializer(WritableNestedSerializer):
 class NestedDeviceRoleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
     device_count = RelatedObjectCountField('devices')
     device_count = RelatedObjectCountField('devices')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
 
 
     class Meta:
     class Meta:
         model = models.DeviceRole
         model = models.DeviceRole
-        fields = ['id', 'url', 'display', 'name', 'slug', 'device_count', 'virtualmachine_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'device_count', 'virtualmachine_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('device_count', 'virtualmachine_count'),
     exclude_fields=('device_count', 'virtualmachine_count'),
 )
 )
 class NestedPlatformSerializer(WritableNestedSerializer):
 class NestedPlatformSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
     device_count = RelatedObjectCountField('devices')
     device_count = RelatedObjectCountField('devices')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
 
 
     class Meta:
     class Meta:
         model = models.Platform
         model = models.Platform
-        fields = ['id', 'url', 'display', 'name', 'slug', 'device_count', 'virtualmachine_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'device_count', 'virtualmachine_count']
 
 
 
 
 class NestedDeviceSerializer(WritableNestedSerializer):
 class NestedDeviceSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
 
 
     class Meta:
     class Meta:
         model = models.Device
         model = models.Device
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
 class ModuleNestedModuleBaySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
 
 
     class Meta:
     class Meta:
         model = models.ModuleBay
         model = models.ModuleBay
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
 class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
 
 
     class Meta:
     class Meta:
         model = models.Module
         model = models.Module
-        fields = ['id', 'url', 'display', 'serial']
+        fields = ['id', 'url', 'display_url', 'display', 'serial']
 
 
 
 
 class NestedModuleSerializer(WritableNestedSerializer):
 class NestedModuleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     module_bay = ModuleNestedModuleBaySerializer(read_only=True)
     module_bay = ModuleNestedModuleBaySerializer(read_only=True)
     module_type = NestedModuleTypeSerializer(read_only=True)
     module_type = NestedModuleTypeSerializer(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Module
         model = models.Module
-        fields = ['id', 'url', 'display', 'device', 'module_bay', 'module_type']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'module_bay', 'module_type']
 
 
 
 
 class NestedConsoleServerPortSerializer(WritableNestedSerializer):
 class NestedConsoleServerPortSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.ConsoleServerPort
         model = models.ConsoleServerPort
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedConsolePortSerializer(WritableNestedSerializer):
 class NestedConsolePortSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.ConsolePort
         model = models.ConsolePort
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedPowerOutletSerializer(WritableNestedSerializer):
 class NestedPowerOutletSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.PowerOutlet
         model = models.PowerOutlet
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedPowerPortSerializer(WritableNestedSerializer):
 class NestedPowerPortSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.PowerPort
         model = models.PowerPort
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedInterfaceSerializer(WritableNestedSerializer):
 class NestedInterfaceSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Interface
         model = models.Interface
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedRearPortSerializer(WritableNestedSerializer):
 class NestedRearPortSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.RearPort
         model = models.RearPort
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedFrontPortSerializer(WritableNestedSerializer):
 class NestedFrontPortSerializer(WritableNestedSerializer):
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.FrontPort
         model = models.FrontPort
-        fields = ['id', 'url', 'display', 'device', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedModuleBaySerializer(WritableNestedSerializer):
 class NestedModuleBaySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
     installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)
     installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = models.ModuleBay
         model = models.ModuleBay
-        fields = ['id', 'url', 'display', 'installed_module', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'installed_module', 'name']
 
 
 
 
 class NestedDeviceBaySerializer(WritableNestedSerializer):
 class NestedDeviceBaySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.DeviceBay
         model = models.DeviceBay
-        fields = ['id', 'url', 'display', 'device', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name']
 
 
 
 
 class NestedInventoryItemSerializer(WritableNestedSerializer):
 class NestedInventoryItemSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
     device = NestedDeviceSerializer(read_only=True)
     device = NestedDeviceSerializer(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.InventoryItem
         model = models.InventoryItem
-        fields = ['id', 'url', 'display', 'device', 'name', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'device', 'name', '_depth']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('inventoryitem_count',),
     exclude_fields=('inventoryitem_count',),
 )
 )
 class NestedInventoryItemRoleSerializer(WritableNestedSerializer):
 class NestedInventoryItemRoleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail')
     inventoryitem_count = RelatedObjectCountField('inventory_items')
     inventoryitem_count = RelatedObjectCountField('inventory_items')
 
 
     class Meta:
     class Meta:
         model = models.InventoryItemRole
         model = models.InventoryItemRole
-        fields = ['id', 'url', 'display', 'name', 'slug', 'inventoryitem_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'inventoryitem_count']
 
 
 
 
 #
 #
@@ -443,11 +406,10 @@ class NestedInventoryItemRoleSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedCableSerializer(WritableNestedSerializer):
 class NestedCableSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
 
 
     class Meta:
     class Meta:
         model = models.Cable
         model = models.Cable
-        fields = ['id', 'url', 'display', 'label']
+        fields = ['id', 'url', 'display_url', 'display', 'label']
 
 
 
 
 #
 #
@@ -458,13 +420,12 @@ class NestedCableSerializer(WritableNestedSerializer):
     exclude_fields=('member_count',),
     exclude_fields=('member_count',),
 )
 )
 class NestedVirtualChassisSerializer(WritableNestedSerializer):
 class NestedVirtualChassisSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
     master = NestedDeviceSerializer()
     master = NestedDeviceSerializer()
     member_count = serializers.IntegerField(read_only=True)
     member_count = serializers.IntegerField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.VirtualChassis
         model = models.VirtualChassis
-        fields = ['id', 'url', 'display', 'name', 'master', 'member_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'master', 'member_count']
 
 
 
 
 #
 #
@@ -475,27 +436,24 @@ class NestedVirtualChassisSerializer(WritableNestedSerializer):
     exclude_fields=('powerfeed_count',),
     exclude_fields=('powerfeed_count',),
 )
 )
 class NestedPowerPanelSerializer(WritableNestedSerializer):
 class NestedPowerPanelSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
     powerfeed_count = RelatedObjectCountField('powerfeeds')
     powerfeed_count = RelatedObjectCountField('powerfeeds')
 
 
     class Meta:
     class Meta:
         model = models.PowerPanel
         model = models.PowerPanel
-        fields = ['id', 'url', 'display', 'name', 'powerfeed_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'powerfeed_count']
 
 
 
 
 class NestedPowerFeedSerializer(WritableNestedSerializer):
 class NestedPowerFeedSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail')
     _occupied = serializers.BooleanField(required=False, read_only=True)
     _occupied = serializers.BooleanField(required=False, read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.PowerFeed
         model = models.PowerFeed
-        fields = ['id', 'url', 'display', 'name', 'cable', '_occupied']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'cable', '_occupied']
 
 
 
 
 class NestedVirtualDeviceContextSerializer(WritableNestedSerializer):
 class NestedVirtualDeviceContextSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
     device = NestedDeviceSerializer()
     device = NestedDeviceSerializer()
 
 
     class Meta:
     class Meta:
         model = models.VirtualDeviceContext
         model = models.VirtualDeviceContext
-        fields = ['id', 'url', 'display', 'name', 'identifier', 'device']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'identifier', 'device']

+ 8 - 10
netbox/dcim/api/serializers_/cables.py

@@ -7,7 +7,7 @@ from dcim.choices import *
 from dcim.constants import *
 from dcim.constants import *
 from dcim.models import Cable, CablePath, CableTermination
 from dcim.models import Cable, CablePath, CableTermination
 from netbox.api.fields import ChoiceField, ContentTypeField
 from netbox.api.fields import ChoiceField, ContentTypeField
-from netbox.api.serializers import GenericObjectSerializer, NetBoxModelSerializer
+from netbox.api.serializers import BaseModelSerializer, GenericObjectSerializer, NetBoxModelSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
 from tenancy.api.serializers_.tenants import TenantSerializer
 from utilities.api import get_serializer_for_model
 from utilities.api import get_serializer_for_model
 
 
@@ -21,7 +21,6 @@ __all__ = (
 
 
 
 
 class CableSerializer(NetBoxModelSerializer):
 class CableSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
     a_terminations = GenericObjectSerializer(many=True, required=False)
     a_terminations = GenericObjectSerializer(many=True, required=False)
     b_terminations = GenericObjectSerializer(many=True, required=False)
     b_terminations = GenericObjectSerializer(many=True, required=False)
     status = ChoiceField(choices=LinkStatusChoices, required=False)
     status = ChoiceField(choices=LinkStatusChoices, required=False)
@@ -31,27 +30,26 @@ class CableSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Cable
         model = Cable
         fields = [
         fields = [
-            'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color',
-            'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant',
+            'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created',
+            'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'label', 'description')
         brief_fields = ('id', 'url', 'display', 'label', 'description')
 
 
 
 
-class TracedCableSerializer(serializers.ModelSerializer):
+class TracedCableSerializer(BaseModelSerializer):
     """
     """
     Used only while tracing a cable path.
     Used only while tracing a cable path.
     """
     """
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
 
 
     class Meta:
     class Meta:
         model = Cable
         model = Cable
         fields = [
         fields = [
-            'id', 'url', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'description',
+            'id', 'url', 'display_url', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'description',
         ]
         ]
 
 
 
 
 class CableTerminationSerializer(NetBoxModelSerializer):
 class CableTerminationSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cabletermination-detail')
     termination_type = ContentTypeField(
     termination_type = ContentTypeField(
         queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)
         queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)
     )
     )
@@ -60,8 +58,8 @@ class CableTerminationSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = CableTermination
         model = CableTermination
         fields = [
         fields = [
-            'id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id', 'termination',
-            'created', 'last_updated',
+            'id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id',
+            'termination', 'created', 'last_updated',
         ]
         ]
 
 
     @extend_schema_field(serializers.JSONField(allow_null=True))
     @extend_schema_field(serializers.JSONField(allow_null=True))

+ 23 - 34
netbox/dcim/api/serializers_/device_components.py

@@ -41,7 +41,6 @@ __all__ = (
 
 
 
 
 class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -63,7 +62,7 @@ class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer,
     class Meta:
     class Meta:
         model = ConsoleServerPort
         model = ConsoleServerPort
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
             'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
             'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'last_updated', '_occupied',
             'last_updated', '_occupied',
@@ -72,7 +71,6 @@ class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer,
 
 
 
 
 class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -94,7 +92,7 @@ class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Conne
     class Meta:
     class Meta:
         model = ConsolePort
         model = ConsolePort
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
             'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
             'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'last_updated', '_occupied',
             'last_updated', '_occupied',
@@ -103,7 +101,6 @@ class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Conne
 
 
 
 
 class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -121,8 +118,8 @@ class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     class Meta:
     class Meta:
         model = PowerPort
         model = PowerPort
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw',
-            'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'maximum_draw',
+            'allocated_draw', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
             'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
             'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
             'created', 'last_updated', '_occupied',
             'created', 'last_updated', '_occupied',
         ]
         ]
@@ -130,7 +127,6 @@ class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
 
 
 
 
 class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -159,8 +155,8 @@ class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, Conne
     class Meta:
     class Meta:
         model = PowerOutlet
         model = PowerOutlet
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'power_port', 'feed_leg',
-            'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'power_port',
+            'feed_leg', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
             'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
             'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
             'created', 'last_updated', '_occupied',
             'created', 'last_updated', '_occupied',
         ]
         ]
@@ -168,7 +164,6 @@ class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, Conne
 
 
 
 
 class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     vdcs = SerializedPKRelatedField(
     vdcs = SerializedPKRelatedField(
         queryset=VirtualDeviceContext.objects.all(),
         queryset=VirtualDeviceContext.objects.all(),
@@ -224,11 +219,11 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     class Meta:
     class Meta:
         model = Interface
         model = Interface
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'vdcs', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge',
-            'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role',
-            'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
-            'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers',
-            'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints',
+            'id', 'url', 'display_url', 'display', 'device', 'vdcs', 'module', 'name', 'label', 'type', 'enabled',
+            'parent', 'bridge', 'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description',
+            'mode', 'rf_role', 'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width',
+            'tx_power', 'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link',
+            'link_peers', 'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
             'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
             'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
         ]
         ]
@@ -250,7 +245,6 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
 
 
 
 
 class RearPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
 class RearPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -263,9 +257,9 @@ class RearPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
     class Meta:
     class Meta:
         model = RearPort
         model = RearPort
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'description',
-            'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created',
-            'last_updated', '_occupied',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'positions',
+            'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'tags',
+            'custom_fields', 'created', 'last_updated', '_occupied',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', 'cable', '_occupied')
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', 'cable', '_occupied')
 
 
@@ -274,15 +268,13 @@ class FrontPortRearPortSerializer(WritableNestedSerializer):
     """
     """
     NestedRearPortSerializer but with parent device omitted (since front and rear ports must belong to same device)
     NestedRearPortSerializer but with parent device omitted (since front and rear ports must belong to same device)
     """
     """
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
 
 
     class Meta:
     class Meta:
         model = RearPort
         model = RearPort
-        fields = ['id', 'url', 'display', 'name', 'label', 'description']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'label', 'description']
 
 
 
 
 class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
 class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module = ModuleSerializer(
     module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -296,7 +288,7 @@ class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
     class Meta:
     class Meta:
         model = FrontPort
         model = FrontPort
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port',
+            'id', 'url', 'display_url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port',
             'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers',
             'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers',
             'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
             'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
         ]
         ]
@@ -304,7 +296,6 @@ class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
 
 
 
 
 class ModuleBaySerializer(NetBoxModelSerializer):
 class ModuleBaySerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     installed_module = ModuleSerializer(
     installed_module = ModuleSerializer(
         nested=True,
         nested=True,
@@ -316,28 +307,26 @@ class ModuleBaySerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ModuleBay
         model = ModuleBay
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'installed_module', 'label', 'position', 'description', 'tags',
-            'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'device', 'name', 'installed_module', 'label', 'position',
+            'description', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'installed_module', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'installed_module', 'name', 'description')
 
 
 
 
 class DeviceBaySerializer(NetBoxModelSerializer):
 class DeviceBaySerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     installed_device = DeviceSerializer(nested=True, required=False, allow_null=True)
     installed_device = DeviceSerializer(nested=True, required=False, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = DeviceBay
         model = DeviceBay
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'name', 'label', 'description', 'installed_device', 'tags',
-            'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'device', 'name', 'label', 'description', 'installed_device',
+            'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description')
 
 
 
 
 class InventoryItemSerializer(NetBoxModelSerializer):
 class InventoryItemSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
     parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
     role = InventoryItemRoleSerializer(nested=True, required=False, allow_null=True)
     role = InventoryItemRoleSerializer(nested=True, required=False, allow_null=True)
@@ -353,9 +342,9 @@ class InventoryItemSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = InventoryItem
         model = InventoryItem
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial',
-            'asset_tag', 'discovered', 'description', 'component_type', 'component_id', 'component', 'tags',
-            'custom_fields', 'created', 'last_updated', '_depth',
+            'id', 'url', 'display_url', 'display', 'device', 'parent', 'name', 'label', 'role', 'manufacturer',
+            'part_id', 'serial', 'asset_tag', 'discovered', 'description', 'component_type', 'component_id',
+            'component', 'tags', 'custom_fields', 'created', 'last_updated', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', '_depth')
         brief_fields = ('id', 'url', 'display', 'device', 'name', 'description', '_depth')
 
 

+ 19 - 22
netbox/dcim/api/serializers_/devices.py

@@ -29,7 +29,6 @@ __all__ = (
 
 
 
 
 class DeviceSerializer(NetBoxModelSerializer):
 class DeviceSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
     device_type = DeviceTypeSerializer(nested=True)
     device_type = DeviceTypeSerializer(nested=True)
     role = DeviceRoleSerializer(nested=True)
     role = DeviceRoleSerializer(nested=True)
     tenant = TenantSerializer(
     tenant = TenantSerializer(
@@ -78,13 +77,13 @@ class DeviceSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Device
         model = Device
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial', 'asset_tag', 'site',
-            'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device', 'status', 'airflow',
-            'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis', 'vc_position',
-            'vc_priority', 'description', 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields',
-            'created', 'last_updated', 'console_port_count', 'console_server_port_count', 'power_port_count',
-            'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count', 'device_bay_count',
-            'module_bay_count', 'inventory_item_count',
+            'id', 'url', 'display_url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial',
+            'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device',
+            'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis',
+            'vc_position', 'vc_priority', 'description', 'comments', 'config_template', 'local_context_data', 'tags',
+            'custom_fields', 'created', 'last_updated', 'console_port_count', 'console_server_port_count',
+            'power_port_count', 'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count',
+            'device_bay_count', 'module_bay_count', 'inventory_item_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
@@ -105,13 +104,13 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
 
 
     class Meta(DeviceSerializer.Meta):
     class Meta(DeviceSerializer.Meta):
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial', 'asset_tag', 'site',
-            'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device', 'status', 'airflow',
-            'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis', 'vc_position',
-            'vc_priority', 'description', 'comments', 'config_template', 'config_context', 'local_context_data', 'tags',
-            'custom_fields', 'created', 'last_updated', 'console_port_count', 'console_server_port_count',
-            'power_port_count', 'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count',
-            'device_bay_count', 'module_bay_count', 'inventory_item_count',
+            'id', 'url', 'display_url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial',
+            'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device',
+            'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis',
+            'vc_position', 'vc_priority', 'description', 'comments', 'config_template', 'config_context',
+            'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', 'console_port_count',
+            'console_server_port_count', 'power_port_count', 'power_outlet_count', 'interface_count',
+            'front_port_count', 'rear_port_count', 'device_bay_count', 'module_bay_count', 'inventory_item_count',
         ]
         ]
 
 
     @extend_schema_field(serializers.JSONField(allow_null=True))
     @extend_schema_field(serializers.JSONField(allow_null=True))
@@ -120,7 +119,6 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
 
 
 
 
 class VirtualDeviceContextSerializer(NetBoxModelSerializer):
 class VirtualDeviceContextSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None)
     identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None)
@@ -135,15 +133,14 @@ class VirtualDeviceContextSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VirtualDeviceContext
         model = VirtualDeviceContext
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip', 'primary_ip4',
-            'primary_ip6', 'status', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
-            'interface_count',
+            'id', 'url', 'display_url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip',
+            'primary_ip4', 'primary_ip6', 'status', 'description', 'comments', 'tags', 'custom_fields',
+            'created', 'last_updated', 'interface_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'identifier', 'device', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'identifier', 'device', 'description')
 
 
 
 
 class ModuleSerializer(NetBoxModelSerializer):
 class ModuleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
     device = DeviceSerializer(nested=True)
     device = DeviceSerializer(nested=True)
     module_bay = NestedModuleBaySerializer()
     module_bay = NestedModuleBaySerializer()
     module_type = ModuleTypeSerializer(nested=True)
     module_type = ModuleTypeSerializer(nested=True)
@@ -152,7 +149,7 @@ class ModuleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Module
         model = Module
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag',
-            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial',
+            'asset_tag', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'device', 'module_bay', 'module_type', 'description')
         brief_fields = ('id', 'url', 'display', 'device', 'module_bay', 'module_type', 'description')

+ 23 - 29
netbox/dcim/api/serializers_/devicetype_components.py

@@ -32,7 +32,6 @@ __all__ = (
 
 
 
 
 class ConsolePortTemplateSerializer(ValidatedModelSerializer):
 class ConsolePortTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleporttemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -54,14 +53,13 @@ class ConsolePortTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ConsolePortTemplate
         model = ConsolePortTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'description', 'created',
-            'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type',
+            'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
 class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverporttemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -83,14 +81,13 @@ class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ConsoleServerPortTemplate
         model = ConsoleServerPortTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'description', 'created',
-            'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type',
+            'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class PowerPortTemplateSerializer(ValidatedModelSerializer):
 class PowerPortTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerporttemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -113,14 +110,13 @@ class PowerPortTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = PowerPortTemplate
         model = PowerPortTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'maximum_draw',
-            'allocated_draw', 'description', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type',
+            'maximum_draw', 'allocated_draw', 'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class PowerOutletTemplateSerializer(ValidatedModelSerializer):
 class PowerOutletTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlettemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -154,14 +150,13 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = PowerOutletTemplate
         model = PowerOutletTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'power_port', 'feed_leg',
-            'description', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type',
+            'power_port', 'feed_leg', 'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class InterfaceTemplateSerializer(ValidatedModelSerializer):
 class InterfaceTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfacetemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -201,14 +196,13 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = InterfaceTemplate
         model = InterfaceTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only',
-            'description', 'bridge', 'poe_mode', 'poe_type', 'rf_role', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled',
+            'mgmt_only', 'description', 'bridge', 'poe_mode', 'poe_type', 'rf_role', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class RearPortTemplateSerializer(ValidatedModelSerializer):
 class RearPortTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         required=False,
         required=False,
         nested=True,
         nested=True,
@@ -226,14 +220,13 @@ class RearPortTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = RearPortTemplate
         model = RearPortTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color', 'positions',
-            'description', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color',
+            'positions', 'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class FrontPortTemplateSerializer(ValidatedModelSerializer):
 class FrontPortTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontporttemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True,
         nested=True,
         required=False,
         required=False,
@@ -252,14 +245,13 @@ class FrontPortTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = FrontPortTemplate
         model = FrontPortTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color', 'rear_port',
-            'rear_port_position', 'description', 'created', 'last_updated',
+            'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color',
+            'rear_port', 'rear_port_position', 'description', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class ModuleBayTemplateSerializer(ValidatedModelSerializer):
 class ModuleBayTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebaytemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True
         nested=True
     )
     )
@@ -267,26 +259,27 @@ class ModuleBayTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ModuleBayTemplate
         model = ModuleBayTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'name', 'label', 'position', 'description', 'created',
-            'last_updated',
+            'id', 'url', 'display', 'device_type', 'name', 'label', 'position', 'description',
+            'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class DeviceBayTemplateSerializer(ValidatedModelSerializer):
 class DeviceBayTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebaytemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True
         nested=True
     )
     )
 
 
     class Meta:
     class Meta:
         model = DeviceBayTemplate
         model = DeviceBayTemplate
-        fields = ['id', 'url', 'display', 'device_type', 'name', 'label', 'description', 'created', 'last_updated']
+        fields = [
+            'id', 'url', 'display', 'device_type', 'name', 'label', 'description',
+            'created', 'last_updated'
+        ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class InventoryItemTemplateSerializer(ValidatedModelSerializer):
 class InventoryItemTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemtemplate-detail')
     device_type = DeviceTypeSerializer(
     device_type = DeviceTypeSerializer(
         nested=True
         nested=True
     )
     )
@@ -313,8 +306,9 @@ class InventoryItemTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = InventoryItemTemplate
         model = InventoryItemTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'device_type', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id',
-            'description', 'component_type', 'component_id', 'component', 'created', 'last_updated', '_depth',
+            'id', 'url', 'display', 'device_type', 'parent', 'name', 'label', 'role', 'manufacturer',
+            'part_id', 'description', 'component_type', 'component_id', 'component', 'created', 'last_updated',
+            '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'description', '_depth')
 
 

+ 9 - 11
netbox/dcim/api/serializers_/devicetypes.py

@@ -17,7 +17,6 @@ __all__ = (
 
 
 
 
 class DeviceTypeSerializer(NetBoxModelSerializer):
 class DeviceTypeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
     manufacturer = ManufacturerSerializer(nested=True)
     manufacturer = ManufacturerSerializer(nested=True)
     default_platform = PlatformSerializer(nested=True, required=False, allow_null=True)
     default_platform = PlatformSerializer(nested=True, required=False, allow_null=True)
     u_height = serializers.DecimalField(
     u_height = serializers.DecimalField(
@@ -51,26 +50,25 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = DeviceType
         model = DeviceType
         fields = [
         fields = [
-            'id', 'url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height',
-            'exclude_from_utilization', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit',
-            'front_image', 'rear_image', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
-            'device_count', 'console_port_template_count', 'console_server_port_template_count',
-            'power_port_template_count', 'power_outlet_template_count', 'interface_template_count',
-            'front_port_template_count', 'rear_port_template_count', 'device_bay_template_count',
-            'module_bay_template_count', 'inventory_item_template_count',
+            'id', 'url', 'display_url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number',
+            'u_height', 'exclude_from_utilization', 'is_full_depth', 'subdevice_role', 'airflow', 'weight',
+            'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags', 'custom_fields',
+            'created', 'last_updated', 'device_count', 'console_port_template_count',
+            'console_server_port_template_count', 'power_port_template_count', 'power_outlet_template_count',
+            'interface_template_count', 'front_port_template_count', 'rear_port_template_count',
+            'device_bay_template_count', 'module_bay_template_count', 'inventory_item_template_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description', 'device_count')
         brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description', 'device_count')
 
 
 
 
 class ModuleTypeSerializer(NetBoxModelSerializer):
 class ModuleTypeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
     manufacturer = ManufacturerSerializer(nested=True)
     manufacturer = ManufacturerSerializer(nested=True)
     weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
     weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = ModuleType
         model = ModuleType
         fields = [
         fields = [
-            'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description',
-            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit',
+            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'description')
         brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'description')

+ 2 - 3
netbox/dcim/api/serializers_/manufacturers.py

@@ -10,7 +10,6 @@ __all__ = (
 
 
 
 
 class ManufacturerSerializer(NetBoxModelSerializer):
 class ManufacturerSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
 
 
     # Related object counts
     # Related object counts
     devicetype_count = RelatedObjectCountField('device_types')
     devicetype_count = RelatedObjectCountField('device_types')
@@ -20,7 +19,7 @@ class ManufacturerSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Manufacturer
         model = Manufacturer
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
-            'devicetype_count', 'inventoryitem_count', 'platform_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'devicetype_count', 'inventoryitem_count', 'platform_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count')

+ 2 - 3
netbox/dcim/api/serializers_/platforms.py

@@ -12,7 +12,6 @@ __all__ = (
 
 
 
 
 class PlatformSerializer(NetBoxModelSerializer):
 class PlatformSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
     manufacturer = ManufacturerSerializer(nested=True, required=False, allow_null=True)
     manufacturer = ManufacturerSerializer(nested=True, required=False, allow_null=True)
     config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
     config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
 
 
@@ -23,7 +22,7 @@ class PlatformSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Platform
         model = Platform
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'manufacturer', 'config_template', 'description', 'tags',
-            'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'manufacturer', 'config_template', 'description',
+            'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count')

+ 6 - 8
netbox/dcim/api/serializers_/power.py

@@ -17,7 +17,6 @@ __all__ = (
 
 
 
 
 class PowerPanelSerializer(NetBoxModelSerializer):
 class PowerPanelSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
     site = SiteSerializer(nested=True)
     site = SiteSerializer(nested=True)
     location = LocationSerializer(
     location = LocationSerializer(
         nested=True,
         nested=True,
@@ -32,14 +31,13 @@ class PowerPanelSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = PowerPanel
         model = PowerPanel
         fields = [
         fields = [
-            'id', 'url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'custom_fields',
-            'powerfeed_count', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags',
+            'custom_fields', 'powerfeed_count', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'powerfeed_count')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'powerfeed_count')
 
 
 
 
 class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
 class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail')
     power_panel = PowerPanelSerializer(nested=True)
     power_panel = PowerPanelSerializer(nested=True)
     rack = RackSerializer(
     rack = RackSerializer(
         nested=True,
         nested=True,
@@ -72,9 +70,9 @@ class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
     class Meta:
     class Meta:
         model = PowerFeed
         model = PowerFeed
         fields = [
         fields = [
-            'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
-            'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
-            'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'description',
-            'tenant', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
+            'id', 'url', 'display_url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply',
+            'phase', 'voltage', 'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers',
+            'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable',
+            'description', 'tenant', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'cable', '_occupied')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'cable', '_occupied')

+ 8 - 11
netbox/dcim/api/serializers_/racks.py

@@ -20,7 +20,6 @@ __all__ = (
 
 
 
 
 class RackRoleSerializer(NetBoxModelSerializer):
 class RackRoleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
 
 
     # Related object counts
     # Related object counts
     rack_count = RelatedObjectCountField('racks')
     rack_count = RelatedObjectCountField('racks')
@@ -28,14 +27,13 @@ class RackRoleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = RackRole
         model = RackRole
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'rack_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'rack_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count')
 
 
 
 
 class RackSerializer(NetBoxModelSerializer):
 class RackSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
     site = SiteSerializer(nested=True)
     site = SiteSerializer(nested=True)
     location = LocationSerializer(nested=True, required=False, allow_null=True, default=None)
     location = LocationSerializer(nested=True, required=False, allow_null=True, default=None)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -55,16 +53,15 @@ class RackSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Rack
         model = Rack
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
-            'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight', 'weight_unit',
-            'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'description', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
+            'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status',
+            'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight',
+            'weight_unit', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'description',
+            'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count')
 
 
 
 
 class RackReservationSerializer(NetBoxModelSerializer):
 class RackReservationSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackreservation-detail')
     rack = RackSerializer(nested=True)
     rack = RackSerializer(nested=True)
     user = UserSerializer(nested=True)
     user = UserSerializer(nested=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -72,8 +69,8 @@ class RackReservationSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = RackReservation
         model = RackReservation
         fields = [
         fields = [
-            'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description',
-            'comments', 'tags', 'custom_fields',
+            'id', 'url', 'display_url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant',
+            'description', 'comments', 'tags', 'custom_fields',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'user', 'description', 'units')
         brief_fields = ('id', 'url', 'display', 'user', 'description', 'units')
 
 

+ 4 - 6
netbox/dcim/api/serializers_/roles.py

@@ -12,7 +12,6 @@ __all__ = (
 
 
 
 
 class DeviceRoleSerializer(NetBoxModelSerializer):
 class DeviceRoleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
     config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
     config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None)
 
 
     # Related object counts
     # Related object counts
@@ -22,14 +21,13 @@ class DeviceRoleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = DeviceRole
         model = DeviceRole
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags',
-            'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template',
+            'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count')
 
 
 
 
 class InventoryItemRoleSerializer(NetBoxModelSerializer):
 class InventoryItemRoleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail')
 
 
     # Related object counts
     # Related object counts
     inventoryitem_count = RelatedObjectCountField('inventory_items')
     inventoryitem_count = RelatedObjectCountField('inventory_items')
@@ -37,7 +35,7 @@ class InventoryItemRoleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = InventoryItemRole
         model = InventoryItemRole
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'inventoryitem_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'inventoryitem_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'inventoryitem_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'inventoryitem_count')

+ 10 - 14
netbox/dcim/api/serializers_/sites.py

@@ -19,35 +19,32 @@ __all__ = (
 
 
 
 
 class RegionSerializer(NestedGroupModelSerializer):
 class RegionSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
     parent = NestedRegionSerializer(required=False, allow_null=True, default=None)
     parent = NestedRegionSerializer(required=False, allow_null=True, default=None)
     site_count = serializers.IntegerField(read_only=True, default=0)
     site_count = serializers.IntegerField(read_only=True, default=0)
 
 
     class Meta:
     class Meta:
         model = Region
         model = Region
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'site_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'site_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
 
 
 
 
 class SiteGroupSerializer(NestedGroupModelSerializer):
 class SiteGroupSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:sitegroup-detail')
     parent = NestedSiteGroupSerializer(required=False, allow_null=True, default=None)
     parent = NestedSiteGroupSerializer(required=False, allow_null=True, default=None)
     site_count = serializers.IntegerField(read_only=True, default=0)
     site_count = serializers.IntegerField(read_only=True, default=0)
 
 
     class Meta:
     class Meta:
         model = SiteGroup
         model = SiteGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'site_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'site_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
 
 
 
 
 class SiteSerializer(NetBoxModelSerializer):
 class SiteSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
     status = ChoiceField(choices=SiteStatusChoices, required=False)
     status = ChoiceField(choices=SiteStatusChoices, required=False)
     region = RegionSerializer(nested=True, required=False, allow_null=True)
     region = RegionSerializer(nested=True, required=False, allow_null=True)
     group = SiteGroupSerializer(nested=True, required=False, allow_null=True)
     group = SiteGroupSerializer(nested=True, required=False, allow_null=True)
@@ -72,16 +69,15 @@ class SiteSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Site
         model = Site
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone',
-            'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'asns', 'tags',
-            'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count', 'prefix_count', 'rack_count',
-            'virtualmachine_count', 'vlan_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility',
+            'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude',
+            'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count',
+            'prefix_count', 'rack_count', 'virtualmachine_count', 'vlan_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'slug')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'slug')
 
 
 
 
 class LocationSerializer(NestedGroupModelSerializer):
 class LocationSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
     site = SiteSerializer(nested=True)
     site = SiteSerializer(nested=True)
     parent = NestedLocationSerializer(required=False, allow_null=True, default=None)
     parent = NestedLocationSerializer(required=False, allow_null=True, default=None)
     status = ChoiceField(choices=LocationStatusChoices, required=False)
     status = ChoiceField(choices=LocationStatusChoices, required=False)
@@ -92,7 +88,7 @@ class LocationSerializer(NestedGroupModelSerializer):
     class Meta:
     class Meta:
         model = Location
         model = Location
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility', 'description',
-            'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility',
+            'description', 'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth')

+ 2 - 3
netbox/dcim/api/serializers_/virtualchassis.py

@@ -10,7 +10,6 @@ __all__ = (
 
 
 
 
 class VirtualChassisSerializer(NetBoxModelSerializer):
 class VirtualChassisSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
     master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
     master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
     members = NestedDeviceSerializer(many=True, read_only=True)
     members = NestedDeviceSerializer(many=True, read_only=True)
 
 
@@ -20,7 +19,7 @@ class VirtualChassisSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VirtualChassis
         model = VirtualChassis
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
-            'created', 'last_updated', 'member_count', 'members',
+            'id', 'url', 'display_url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated', 'member_count', 'members',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'master', 'description', 'member_count')
         brief_fields = ('id', 'url', 'display', 'name', 'master', 'description', 'member_count')

+ 16 - 23
netbox/extras/api/nested_serializers.py

@@ -22,79 +22,69 @@ __all__ = [
 
 
 
 
 class NestedEventRuleSerializer(WritableNestedSerializer):
 class NestedEventRuleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:eventrule-detail')
 
 
     class Meta:
     class Meta:
         model = models.EventRule
         model = models.EventRule
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedWebhookSerializer(WritableNestedSerializer):
 class NestedWebhookSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:webhook-detail')
 
 
     class Meta:
     class Meta:
         model = models.Webhook
         model = models.Webhook
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedCustomFieldSerializer(WritableNestedSerializer):
 class NestedCustomFieldSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
 
 
     class Meta:
     class Meta:
         model = models.CustomField
         model = models.CustomField
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedCustomFieldChoiceSetSerializer(WritableNestedSerializer):
 class NestedCustomFieldChoiceSetSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfieldchoiceset-detail')
 
 
     class Meta:
     class Meta:
         model = models.CustomFieldChoiceSet
         model = models.CustomFieldChoiceSet
-        fields = ['id', 'url', 'display', 'name', 'choices_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'choices_count']
 
 
 
 
 class NestedCustomLinkSerializer(WritableNestedSerializer):
 class NestedCustomLinkSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customlink-detail')
 
 
     class Meta:
     class Meta:
         model = models.CustomLink
         model = models.CustomLink
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedConfigContextSerializer(WritableNestedSerializer):
 class NestedConfigContextSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
 
 
     class Meta:
     class Meta:
         model = models.ConfigContext
         model = models.ConfigContext
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedConfigTemplateSerializer(WritableNestedSerializer):
 class NestedConfigTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ConfigTemplate
         model = models.ConfigTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedExportTemplateSerializer(WritableNestedSerializer):
 class NestedExportTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ExportTemplate
         model = models.ExportTemplate
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedSavedFilterSerializer(WritableNestedSerializer):
 class NestedSavedFilterSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:savedfilter-detail')
 
 
     class Meta:
     class Meta:
         model = models.SavedFilter
         model = models.SavedFilter
-        fields = ['id', 'url', 'display', 'name', 'slug']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug']
 
 
 
 
 class NestedBookmarkSerializer(WritableNestedSerializer):
 class NestedBookmarkSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:bookmark-detail')
 
 
     class Meta:
     class Meta:
         model = models.Bookmark
         model = models.Bookmark
@@ -102,7 +92,6 @@ class NestedBookmarkSerializer(WritableNestedSerializer):
 
 
 
 
 class NestedImageAttachmentSerializer(WritableNestedSerializer):
 class NestedImageAttachmentSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:imageattachment-detail')
 
 
     class Meta:
     class Meta:
         model = models.ImageAttachment
         model = models.ImageAttachment
@@ -110,11 +99,10 @@ class NestedImageAttachmentSerializer(WritableNestedSerializer):
 
 
 
 
 class NestedJournalEntrySerializer(WritableNestedSerializer):
 class NestedJournalEntrySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:journalentry-detail')
 
 
     class Meta:
     class Meta:
         model = models.JournalEntry
         model = models.JournalEntry
-        fields = ['id', 'url', 'display', 'created']
+        fields = ['id', 'url', 'display_url', 'display', 'created']
 
 
 
 
 class NestedScriptSerializer(WritableNestedSerializer):
 class NestedScriptSerializer(WritableNestedSerializer):
@@ -123,12 +111,17 @@ class NestedScriptSerializer(WritableNestedSerializer):
         lookup_field='full_name',
         lookup_field='full_name',
         lookup_url_kwarg='pk'
         lookup_url_kwarg='pk'
     )
     )
+    display_url = serializers.HyperlinkedIdentityField(
+        view_name='extras:script',
+        lookup_field='full_name',
+        lookup_url_kwarg='pk'
+    )
     name = serializers.CharField(read_only=True)
     name = serializers.CharField(read_only=True)
     display = serializers.SerializerMethodField(read_only=True)
     display = serializers.SerializerMethodField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Script
         model = models.Script
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
     def get_display(self, obj):
     def get_display(self, obj):
         return f'{obj.name} ({obj.module})'
         return f'{obj.name} ({obj.module})'

+ 2 - 3
netbox/extras/api/serializers_/attachments.py

@@ -14,7 +14,6 @@ __all__ = (
 
 
 
 
 class ImageAttachmentSerializer(ValidatedModelSerializer):
 class ImageAttachmentSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:imageattachment-detail')
     object_type = ContentTypeField(
     object_type = ContentTypeField(
         queryset=ObjectType.objects.all()
         queryset=ObjectType.objects.all()
     )
     )
@@ -23,8 +22,8 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ImageAttachment
         model = ImageAttachment
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_type', 'object_id', 'parent', 'name', 'image', 'image_height',
-            'image_width', 'created', 'last_updated',
+            'id', 'url', 'display', 'object_type', 'object_id', 'parent', 'name', 'image',
+            'image_height', 'image_width', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'image')
         brief_fields = ('id', 'url', 'display', 'name', 'image')
 
 

+ 0 - 1
netbox/extras/api/serializers_/bookmarks.py

@@ -14,7 +14,6 @@ __all__ = (
 
 
 
 
 class BookmarkSerializer(ValidatedModelSerializer):
 class BookmarkSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:bookmark-detail')
     object_type = ContentTypeField(
     object_type = ContentTypeField(
         queryset=ObjectType.objects.with_feature('bookmarks'),
         queryset=ObjectType.objects.with_feature('bookmarks'),
     )
     )

+ 4 - 5
netbox/extras/api/serializers_/configcontexts.py

@@ -20,7 +20,6 @@ __all__ = (
 
 
 
 
 class ConfigContextSerializer(ValidatedModelSerializer):
 class ConfigContextSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
     regions = SerializedPKRelatedField(
     regions = SerializedPKRelatedField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         serializer=RegionSerializer,
         serializer=RegionSerializer,
@@ -123,9 +122,9 @@ class ConfigContextSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ConfigContext
         model = ConfigContext
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'weight', 'description', 'is_active', 'regions', 'site_groups', 'sites',
-            'locations', 'device_types', 'roles', 'platforms', 'cluster_types', 'cluster_groups', 'clusters',
-            'tenant_groups', 'tenants', 'tags', 'data_source', 'data_path', 'data_file', 'data_synced', 'data',
-            'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'weight', 'description', 'is_active', 'regions',
+            'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types',
+            'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data_source', 'data_path',
+            'data_file', 'data_synced', 'data', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 2 - 3
netbox/extras/api/serializers_/configtemplates.py

@@ -11,7 +11,6 @@ __all__ = (
 
 
 
 
 class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
 class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
     data_source = DataSourceSerializer(
     data_source = DataSourceSerializer(
         nested=True,
         nested=True,
         required=False
         required=False
@@ -24,7 +23,7 @@ class ConfigTemplateSerializer(TaggableModelSerializer, ValidatedModelSerializer
     class Meta:
     class Meta:
         model = ConfigTemplate
         model = ConfigTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'description', 'environment_params', 'template_code', 'data_source',
-            'data_path', 'data_file', 'data_synced', 'tags', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'environment_params', 'template_code',
+            'data_source', 'data_path', 'data_file', 'data_synced', 'tags', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 6 - 8
netbox/extras/api/serializers_/customfields.py

@@ -16,7 +16,6 @@ __all__ = (
 
 
 
 
 class CustomFieldChoiceSetSerializer(ValidatedModelSerializer):
 class CustomFieldChoiceSetSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfieldchoiceset-detail')
     base_choices = ChoiceField(
     base_choices = ChoiceField(
         choices=CustomFieldChoiceSetBaseChoices,
         choices=CustomFieldChoiceSetBaseChoices,
         required=False
         required=False
@@ -31,14 +30,13 @@ class CustomFieldChoiceSetSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = CustomFieldChoiceSet
         model = CustomFieldChoiceSet
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
-            'choices_count', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'base_choices', 'extra_choices',
+            'order_alphabetically', 'choices_count', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
 
 
 
 
 class CustomFieldSerializer(ValidatedModelSerializer):
 class CustomFieldSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.with_feature('custom_fields'),
         queryset=ObjectType.objects.with_feature('custom_fields'),
         many=True
         many=True
@@ -62,10 +60,10 @@ class CustomFieldSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = CustomField
         model = CustomField
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_types', 'type', 'related_object_type', 'data_type', 'name', 'label',
-            'group_name', 'description', 'required', 'search_weight', 'filter_logic', 'ui_visible', 'ui_editable',
-            'is_cloneable', 'default', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex',
-            'validation_unique', 'choice_set', 'comments', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type',
+            'name', 'label', 'group_name', 'description', 'required', 'search_weight', 'filter_logic', 'ui_visible',
+            'ui_editable', 'is_cloneable', 'default', 'weight', 'validation_minimum', 'validation_maximum',
+            'validation_regex', 'validation_unique', 'choice_set', 'comments', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 

+ 2 - 3
netbox/extras/api/serializers_/customlinks.py

@@ -11,7 +11,6 @@ __all__ = (
 
 
 
 
 class CustomLinkSerializer(ValidatedModelSerializer):
 class CustomLinkSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customlink-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.with_feature('custom_links'),
         queryset=ObjectType.objects.with_feature('custom_links'),
         many=True
         many=True
@@ -20,7 +19,7 @@ class CustomLinkSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = CustomLink
         model = CustomLink
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_types', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name',
-            'button_class', 'new_window', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'link_text', 'link_url',
+            'weight', 'group_name', 'button_class', 'new_window', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name')
         brief_fields = ('id', 'url', 'display', 'name')

+ 4 - 6
netbox/extras/api/serializers_/events.py

@@ -21,7 +21,6 @@ __all__ = (
 #
 #
 
 
 class EventRuleSerializer(NetBoxModelSerializer):
 class EventRuleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:eventrule-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.with_feature('event_rules'),
         queryset=ObjectType.objects.with_feature('event_rules'),
         many=True
         many=True
@@ -35,7 +34,7 @@ class EventRuleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = EventRule
         model = EventRule
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_types', 'name', 'type_create', 'type_update', 'type_delete',
+            'id', 'url', 'display_url', 'display', 'object_types', 'name', 'type_create', 'type_update', 'type_delete',
             'type_job_start', 'type_job_end', 'enabled', 'conditions', 'action_type', 'action_object_type',
             'type_job_start', 'type_job_end', 'enabled', 'conditions', 'action_type', 'action_object_type',
             'action_object_id', 'action_object', 'description', 'custom_fields', 'tags', 'created', 'last_updated',
             'action_object_id', 'action_object', 'description', 'custom_fields', 'tags', 'created', 'last_updated',
         ]
         ]
@@ -58,13 +57,12 @@ class EventRuleSerializer(NetBoxModelSerializer):
 #
 #
 
 
 class WebhookSerializer(NetBoxModelSerializer):
 class WebhookSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:webhook-detail')
 
 
     class Meta:
     class Meta:
         model = Webhook
         model = Webhook
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'description', 'payload_url', 'http_method', 'http_content_type',
-            'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path', 'custom_fields',
-            'tags', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'payload_url', 'http_method',
+            'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path',
+            'custom_fields', 'tags', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 1 - 2
netbox/extras/api/serializers_/exporttemplates.py

@@ -12,7 +12,6 @@ __all__ = (
 
 
 
 
 class ExportTemplateSerializer(ValidatedModelSerializer):
 class ExportTemplateSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.with_feature('export_templates'),
         queryset=ObjectType.objects.with_feature('export_templates'),
         many=True
         many=True
@@ -29,7 +28,7 @@ class ExportTemplateSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ExportTemplate
         model = ExportTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_types', 'name', 'description', 'template_code', 'mime_type',
+            'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'template_code', 'mime_type',
             'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'data_synced', 'created',
             'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'data_synced', 'created',
             'last_updated',
             'last_updated',
         ]
         ]

+ 2 - 3
netbox/extras/api/serializers_/journaling.py

@@ -16,7 +16,6 @@ __all__ = (
 
 
 
 
 class JournalEntrySerializer(NetBoxModelSerializer):
 class JournalEntrySerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:journalentry-detail')
     assigned_object_type = ContentTypeField(
     assigned_object_type = ContentTypeField(
         queryset=ObjectType.objects.all()
         queryset=ObjectType.objects.all()
     )
     )
@@ -35,8 +34,8 @@ class JournalEntrySerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = JournalEntry
         model = JournalEntry
         fields = [
         fields = [
-            'id', 'url', 'display', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'created',
-            'created_by', 'kind', 'comments', 'tags', 'custom_fields', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'assigned_object_type', 'assigned_object_id', 'assigned_object',
+            'created', 'created_by', 'kind', 'comments', 'tags', 'custom_fields', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'created')
         brief_fields = ('id', 'url', 'display', 'created')
 
 

+ 2 - 3
netbox/extras/api/serializers_/savedfilters.py

@@ -11,7 +11,6 @@ __all__ = (
 
 
 
 
 class SavedFilterSerializer(ValidatedModelSerializer):
 class SavedFilterSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:savedfilter-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
         many=True
         many=True
@@ -20,7 +19,7 @@ class SavedFilterSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = SavedFilter
         model = SavedFilter
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_types', 'name', 'slug', 'description', 'user', 'weight', 'enabled',
-            'shared', 'parameters', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'object_types', 'name', 'slug', 'description', 'user', 'weight',
+            'enabled', 'shared', 'parameters', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')

+ 1 - 2
netbox/extras/api/serializers_/scripts.py

@@ -14,7 +14,6 @@ __all__ = (
 
 
 
 
 class ScriptSerializer(ValidatedModelSerializer):
 class ScriptSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:script-detail')
     description = serializers.SerializerMethodField(read_only=True)
     description = serializers.SerializerMethodField(read_only=True)
     vars = serializers.SerializerMethodField(read_only=True)
     vars = serializers.SerializerMethodField(read_only=True)
     result = JobSerializer(nested=True, read_only=True)
     result = JobSerializer(nested=True, read_only=True)
@@ -22,7 +21,7 @@ class ScriptSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = Script
         model = Script
         fields = [
         fields = [
-            'id', 'url', 'module', 'name', 'description', 'vars', 'result', 'display', 'is_executable',
+            'id', 'url', 'display_url', 'module', 'name', 'description', 'vars', 'result', 'display', 'is_executable',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 

+ 2 - 3
netbox/extras/api/serializers_/tags.py

@@ -11,7 +11,6 @@ __all__ = (
 
 
 
 
 class TagSerializer(ValidatedModelSerializer):
 class TagSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:tag-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.with_feature('tags'),
         queryset=ObjectType.objects.with_feature('tags'),
         many=True,
         many=True,
@@ -24,7 +23,7 @@ class TagSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = Tag
         model = Tag
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'object_types', 'tagged_items', 'created',
-            'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'object_types',
+            'tagged_items', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'color', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'color', 'description')

+ 16 - 32
netbox/ipam/api/nested_serializers.py

@@ -31,11 +31,10 @@ __all__ = [
 #
 #
 
 
 class NestedASNRangeSerializer(WritableNestedSerializer):
 class NestedASNRangeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asnrange-detail')
 
 
     class Meta:
     class Meta:
         model = models.ASNRange
         model = models.ASNRange
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 #
 #
@@ -43,11 +42,10 @@ class NestedASNRangeSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedASNSerializer(WritableNestedSerializer):
 class NestedASNSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
 
 
     class Meta:
     class Meta:
         model = models.ASN
         model = models.ASN
-        fields = ['id', 'url', 'display', 'asn']
+        fields = ['id', 'url', 'display_url', 'display', 'asn']
 
 
 
 
 #
 #
@@ -58,12 +56,11 @@ class NestedASNSerializer(WritableNestedSerializer):
     exclude_fields=('prefix_count',),
     exclude_fields=('prefix_count',),
 )
 )
 class NestedVRFSerializer(WritableNestedSerializer):
 class NestedVRFSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
     prefix_count = RelatedObjectCountField('prefixes')
     prefix_count = RelatedObjectCountField('prefixes')
 
 
     class Meta:
     class Meta:
         model = models.VRF
         model = models.VRF
-        fields = ['id', 'url', 'display', 'name', 'rd', 'prefix_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'rd', 'prefix_count']
 
 
 
 
 #
 #
@@ -71,11 +68,10 @@ class NestedVRFSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedRouteTargetSerializer(WritableNestedSerializer):
 class NestedRouteTargetSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
 
 
     class Meta:
     class Meta:
         model = models.RouteTarget
         model = models.RouteTarget
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 #
 #
@@ -86,21 +82,19 @@ class NestedRouteTargetSerializer(WritableNestedSerializer):
     exclude_fields=('aggregate_count',),
     exclude_fields=('aggregate_count',),
 )
 )
 class NestedRIRSerializer(WritableNestedSerializer):
 class NestedRIRSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
     aggregate_count = RelatedObjectCountField('aggregates')
     aggregate_count = RelatedObjectCountField('aggregates')
 
 
     class Meta:
     class Meta:
         model = models.RIR
         model = models.RIR
-        fields = ['id', 'url', 'display', 'name', 'slug', 'aggregate_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'aggregate_count']
 
 
 
 
 class NestedAggregateSerializer(WritableNestedSerializer):
 class NestedAggregateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail')
     family = serializers.IntegerField(read_only=True)
     family = serializers.IntegerField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Aggregate
         model = models.Aggregate
-        fields = ['id', 'url', 'display', 'family', 'prefix']
+        fields = ['id', 'url', 'display_url', 'display', 'family', 'prefix']
 
 
 
 
 #
 #
@@ -108,20 +102,18 @@ class NestedAggregateSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedFHRPGroupSerializer(WritableNestedSerializer):
 class NestedFHRPGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroup-detail')
 
 
     class Meta:
     class Meta:
         model = models.FHRPGroup
         model = models.FHRPGroup
-        fields = ['id', 'url', 'display', 'protocol', 'group_id']
+        fields = ['id', 'url', 'display_url', 'display', 'protocol', 'group_id']
 
 
 
 
 class NestedFHRPGroupAssignmentSerializer(WritableNestedSerializer):
 class NestedFHRPGroupAssignmentSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail')
     group = NestedFHRPGroupSerializer()
     group = NestedFHRPGroupSerializer()
 
 
     class Meta:
     class Meta:
         model = models.FHRPGroupAssignment
         model = models.FHRPGroupAssignment
-        fields = ['id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'priority']
+        fields = ['id', 'url', 'display_url', 'display', 'group', 'interface_type', 'interface_id', 'priority']
 
 
 
 
 #
 #
@@ -132,33 +124,30 @@ class NestedFHRPGroupAssignmentSerializer(WritableNestedSerializer):
     exclude_fields=('prefix_count', 'vlan_count'),
     exclude_fields=('prefix_count', 'vlan_count'),
 )
 )
 class NestedRoleSerializer(WritableNestedSerializer):
 class NestedRoleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail')
     prefix_count = RelatedObjectCountField('prefixes')
     prefix_count = RelatedObjectCountField('prefixes')
     vlan_count = RelatedObjectCountField('vlans')
     vlan_count = RelatedObjectCountField('vlans')
 
 
     class Meta:
     class Meta:
         model = models.Role
         model = models.Role
-        fields = ['id', 'url', 'display', 'name', 'slug', 'prefix_count', 'vlan_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'prefix_count', 'vlan_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('vlan_count',),
     exclude_fields=('vlan_count',),
 )
 )
 class NestedVLANGroupSerializer(WritableNestedSerializer):
 class NestedVLANGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlangroup-detail')
     vlan_count = RelatedObjectCountField('vlans')
     vlan_count = RelatedObjectCountField('vlans')
 
 
     class Meta:
     class Meta:
         model = models.VLANGroup
         model = models.VLANGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'vlan_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'vlan_count']
 
 
 
 
 class NestedVLANSerializer(WritableNestedSerializer):
 class NestedVLANSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
 
 
     class Meta:
     class Meta:
         model = models.VLAN
         model = models.VLAN
-        fields = ['id', 'url', 'display', 'vid', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'vid', 'name']
 
 
 
 
 #
 #
@@ -166,13 +155,12 @@ class NestedVLANSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedPrefixSerializer(WritableNestedSerializer):
 class NestedPrefixSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:prefix-detail')
     family = serializers.IntegerField(read_only=True)
     family = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(read_only=True)
 
 
     class Meta:
     class Meta:
         model = models.Prefix
         model = models.Prefix
-        fields = ['id', 'url', 'display', 'family', 'prefix', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'family', 'prefix', '_depth']
 
 
 
 
 #
 #
@@ -180,14 +168,13 @@ class NestedPrefixSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedIPRangeSerializer(WritableNestedSerializer):
 class NestedIPRangeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:iprange-detail')
     family = serializers.IntegerField(read_only=True)
     family = serializers.IntegerField(read_only=True)
     start_address = IPAddressField()
     start_address = IPAddressField()
     end_address = IPAddressField()
     end_address = IPAddressField()
 
 
     class Meta:
     class Meta:
         model = models.IPRange
         model = models.IPRange
-        fields = ['id', 'url', 'display', 'family', 'start_address', 'end_address']
+        fields = ['id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address']
 
 
 
 
 #
 #
@@ -195,13 +182,12 @@ class NestedIPRangeSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedIPAddressSerializer(WritableNestedSerializer):
 class NestedIPAddressSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
     family = serializers.IntegerField(read_only=True)
     family = serializers.IntegerField(read_only=True)
     address = IPAddressField()
     address = IPAddressField()
 
 
     class Meta:
     class Meta:
         model = models.IPAddress
         model = models.IPAddress
-        fields = ['id', 'url', 'display', 'family', 'address']
+        fields = ['id', 'url', 'display_url', 'display', 'family', 'address']
 
 
 
 
 #
 #
@@ -209,16 +195,14 @@ class NestedIPAddressSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedServiceTemplateSerializer(WritableNestedSerializer):
 class NestedServiceTemplateSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:servicetemplate-detail')
 
 
     class Meta:
     class Meta:
         model = models.ServiceTemplate
         model = models.ServiceTemplate
-        fields = ['id', 'url', 'display', 'name', 'protocol', 'ports']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'protocol', 'ports']
 
 
 
 
 class NestedServiceSerializer(WritableNestedSerializer):
 class NestedServiceSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:service-detail')
 
 
     class Meta:
     class Meta:
         model = models.Service
         model = models.Service
-        fields = ['id', 'url', 'display', 'name', 'protocol', 'ports']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'protocol', 'ports']

+ 6 - 9
netbox/ipam/api/serializers_/asns.py

@@ -14,7 +14,6 @@ __all__ = (
 
 
 
 
 class RIRSerializer(NetBoxModelSerializer):
 class RIRSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:rir-detail')
 
 
     # Related object counts
     # Related object counts
     aggregate_count = RelatedObjectCountField('aggregates')
     aggregate_count = RelatedObjectCountField('aggregates')
@@ -22,14 +21,13 @@ class RIRSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = RIR
         model = RIR
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'is_private', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'aggregate_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'is_private', 'description', 'tags',
+            'custom_fields', 'created', 'last_updated', 'aggregate_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count')
 
 
 
 
 class ASNRangeSerializer(NetBoxModelSerializer):
 class ASNRangeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asnrange-detail')
     rir = RIRSerializer(nested=True)
     rir = RIRSerializer(nested=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     asn_count = serializers.IntegerField(read_only=True)
     asn_count = serializers.IntegerField(read_only=True)
@@ -37,14 +35,13 @@ class ASNRangeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ASNRange
         model = ASNRange
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'rir', 'start', 'end', 'tenant', 'description', 'tags',
-            'custom_fields', 'created', 'last_updated', 'asn_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'rir', 'start', 'end', 'tenant', 'description',
+            'tags', 'custom_fields', 'created', 'last_updated', 'asn_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class ASNSerializer(NetBoxModelSerializer):
 class ASNSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
     rir = RIRSerializer(nested=True, required=False, allow_null=True)
     rir = RIRSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
 
 
@@ -55,8 +52,8 @@ class ASNSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ASN
         model = ASN
         fields = [
         fields = [
-            'id', 'url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags', 'custom_fields',
-            'created', 'last_updated', 'site_count', 'provider_count',
+            'id', 'url', 'display_url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated', 'site_count', 'provider_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'asn', 'description')
         brief_fields = ('id', 'url', 'display', 'asn', 'description')
 
 

+ 4 - 6
netbox/ipam/api/serializers_/fhrpgroups.py

@@ -15,20 +15,18 @@ __all__ = (
 
 
 
 
 class FHRPGroupSerializer(NetBoxModelSerializer):
 class FHRPGroupSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroup-detail')
     ip_addresses = IPAddressSerializer(nested=True, many=True, read_only=True)
     ip_addresses = IPAddressSerializer(nested=True, many=True, read_only=True)
 
 
     class Meta:
     class Meta:
         model = FHRPGroup
         model = FHRPGroup
         fields = [
         fields = [
-            'id', 'name', 'url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key', 'description', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated', 'ip_addresses',
+            'id', 'name', 'url', 'display_url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key',
+            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'ip_addresses',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'protocol', 'group_id', 'description')
         brief_fields = ('id', 'url', 'display', 'protocol', 'group_id', 'description')
 
 
 
 
 class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
 class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:fhrpgroupassignment-detail')
     group = FHRPGroupSerializer(nested=True)
     group = FHRPGroupSerializer(nested=True)
     interface_type = ContentTypeField(
     interface_type = ContentTypeField(
         queryset=ContentType.objects.all()
         queryset=ContentType.objects.all()
@@ -38,8 +36,8 @@ class FHRPGroupAssignmentSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = FHRPGroupAssignment
         model = FHRPGroupAssignment
         fields = [
         fields = [
-            'id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'interface', 'priority', 'created',
-            'last_updated',
+            'id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'interface',
+            'priority', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'priority')
         brief_fields = ('id', 'url', 'display', 'group', 'interface_type', 'interface_id', 'priority')
 
 

+ 10 - 14
netbox/ipam/api/serializers_/ip.py

@@ -29,7 +29,6 @@ __all__ = (
 
 
 
 
 class AggregateSerializer(NetBoxModelSerializer):
 class AggregateSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:aggregate-detail')
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     rir = RIRSerializer(nested=True)
     rir = RIRSerializer(nested=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -38,14 +37,13 @@ class AggregateSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Aggregate
         model = Aggregate
         fields = [
         fields = [
-            'id', 'url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description',
+            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description')
         brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description')
 
 
 
 
 class PrefixSerializer(NetBoxModelSerializer):
 class PrefixSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:prefix-detail')
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     vrf = VRFSerializer(nested=True, required=False, allow_null=True)
     vrf = VRFSerializer(nested=True, required=False, allow_null=True)
@@ -60,9 +58,9 @@ class PrefixSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Prefix
         model = Prefix
         fields = [
         fields = [
-            'id', 'url', 'display', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool',
-            'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'children',
-            '_depth',
+            'id', 'url', 'display_url', 'display', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status',
+            'role', 'is_pool', 'mark_utilized', 'description', 'comments', 'tags', 'custom_fields',
+            'created', 'last_updated', 'children', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth')
         brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth')
 
 
@@ -119,7 +117,6 @@ class AvailablePrefixSerializer(serializers.Serializer):
 #
 #
 
 
 class IPRangeSerializer(NetBoxModelSerializer):
 class IPRangeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:iprange-detail')
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     start_address = IPAddressField()
     start_address = IPAddressField()
     end_address = IPAddressField()
     end_address = IPAddressField()
@@ -131,8 +128,8 @@ class IPRangeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IPRange
         model = IPRange
         fields = [
         fields = [
-            'id', 'url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant', 'status', 'role',
-            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant',
+            'status', 'role', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
             'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
             'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description')
         brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description')
@@ -143,7 +140,6 @@ class IPRangeSerializer(NetBoxModelSerializer):
 #
 #
 
 
 class IPAddressSerializer(NetBoxModelSerializer):
 class IPAddressSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
     address = IPAddressField()
     address = IPAddressField()
     vrf = VRFSerializer(nested=True, required=False, allow_null=True)
     vrf = VRFSerializer(nested=True, required=False, allow_null=True)
@@ -162,9 +158,9 @@ class IPAddressSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IPAddress
         model = IPAddress
         fields = [
         fields = [
-            'id', 'url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'assigned_object_type',
-            'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside', 'dns_name', 'description', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role',
+            'assigned_object_type', 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside',
+            'dns_name', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'family', 'address', 'description')
         brief_fields = ('id', 'url', 'display', 'family', 'address', 'description')
 
 

+ 2 - 3
netbox/ipam/api/serializers_/roles.py

@@ -10,7 +10,6 @@ __all__ = (
 
 
 
 
 class RoleSerializer(NetBoxModelSerializer):
 class RoleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:role-detail')
 
 
     # Related object counts
     # Related object counts
     prefix_count = RelatedObjectCountField('prefixes')
     prefix_count = RelatedObjectCountField('prefixes')
@@ -19,7 +18,7 @@ class RoleSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Role
         model = Role
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'weight', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'prefix_count', 'vlan_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'weight', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'prefix_count', 'vlan_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'prefix_count', 'vlan_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'prefix_count', 'vlan_count')

+ 4 - 6
netbox/ipam/api/serializers_/services.py

@@ -15,20 +15,18 @@ __all__ = (
 
 
 
 
 class ServiceTemplateSerializer(NetBoxModelSerializer):
 class ServiceTemplateSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:servicetemplate-detail')
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
 
 
     class Meta:
     class Meta:
         model = ServiceTemplate
         model = ServiceTemplate
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'custom_fields',
-            'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'protocol', 'ports', 'description', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')
 
 
 
 
 class ServiceSerializer(NetBoxModelSerializer):
 class ServiceSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:service-detail')
     device = DeviceSerializer(nested=True, required=False, allow_null=True)
     device = DeviceSerializer(nested=True, required=False, allow_null=True)
     virtual_machine = VirtualMachineSerializer(nested=True, required=False, allow_null=True)
     virtual_machine = VirtualMachineSerializer(nested=True, required=False, allow_null=True)
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
     protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
@@ -43,7 +41,7 @@ class ServiceSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Service
         model = Service
         fields = [
         fields = [
-            'id', 'url', 'display', 'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses',
-            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'device', 'virtual_machine', 'name', 'protocol', 'ports',
+            'ipaddresses', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')

+ 5 - 6
netbox/ipam/api/serializers_/vlans.py

@@ -22,7 +22,6 @@ __all__ = (
 
 
 
 
 class VLANGroupSerializer(NetBoxModelSerializer):
 class VLANGroupSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlangroup-detail')
     scope_type = ContentTypeField(
     scope_type = ContentTypeField(
         queryset=ContentType.objects.filter(
         queryset=ContentType.objects.filter(
             model__in=VLANGROUP_SCOPE_TYPES
             model__in=VLANGROUP_SCOPE_TYPES
@@ -41,8 +40,8 @@ class VLANGroupSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VLANGroup
         model = VLANGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'min_vid', 'max_vid',
-            'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization'
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'min_vid',
+            'max_vid', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization'
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count')
         validators = []
         validators = []
@@ -57,7 +56,6 @@ class VLANGroupSerializer(NetBoxModelSerializer):
 
 
 
 
 class VLANSerializer(NetBoxModelSerializer):
 class VLANSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vlan-detail')
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     site = SiteSerializer(nested=True, required=False, allow_null=True)
     group = VLANGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     group = VLANGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -71,8 +69,9 @@ class VLANSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VLAN
         model = VLAN
         fields = [
         fields = [
-            'id', 'url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description',
-            'comments', 'l2vpn_termination', 'tags', 'custom_fields', 'created', 'last_updated', 'prefix_count',
+            'id', 'url', 'display_url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role',
+            'description', 'comments', 'l2vpn_termination', 'tags', 'custom_fields', 'created', 'last_updated',
+            'prefix_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'vid', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'vid', 'name', 'description')
 
 

+ 3 - 5
netbox/ipam/api/serializers_/vrfs.py

@@ -12,20 +12,18 @@ __all__ = (
 
 
 
 
 class RouteTargetSerializer(NetBoxModelSerializer):
 class RouteTargetSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:routetarget-detail')
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
 
 
     class Meta:
     class Meta:
         model = RouteTarget
         model = RouteTarget
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created',
-            'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'tenant', 'description', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class VRFSerializer(NetBoxModelSerializer):
 class VRFSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     tenant = TenantSerializer(nested=True, required=False, allow_null=True)
     import_targets = SerializedPKRelatedField(
     import_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
@@ -47,7 +45,7 @@ class VRFSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VRF
         model = VRF
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments',
+            'id', 'url', 'display_url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments',
             'import_targets', 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated', 'ipaddress_count',
             'import_targets', 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated', 'ipaddress_count',
             'prefix_count',
             'prefix_count',
         ]
         ]

+ 3 - 0
netbox/netbox/api/serializers/base.py

@@ -6,6 +6,7 @@ from drf_spectacular.utils import extend_schema_field
 from drf_spectacular.types import OpenApiTypes
 from drf_spectacular.types import OpenApiTypes
 
 
 from utilities.api import get_related_object_by_attrs
 from utilities.api import get_related_object_by_attrs
+from .fields import NetBoxAPIHyperlinkedIdentityField, NetBoxURLHyperlinkedIdentityField
 
 
 __all__ = (
 __all__ = (
     'BaseModelSerializer',
     'BaseModelSerializer',
@@ -14,6 +15,8 @@ __all__ = (
 
 
 
 
 class BaseModelSerializer(serializers.ModelSerializer):
 class BaseModelSerializer(serializers.ModelSerializer):
+    url = NetBoxAPIHyperlinkedIdentityField()
+    display_url = NetBoxURLHyperlinkedIdentityField()
     display = serializers.SerializerMethodField(read_only=True)
     display = serializers.SerializerMethodField(read_only=True)
 
 
     def __init__(self, *args, nested=False, fields=None, **kwargs):
     def __init__(self, *args, nested=False, fields=None, **kwargs):

+ 53 - 0
netbox/netbox/api/serializers/fields.py

@@ -0,0 +1,53 @@
+from rest_framework import serializers
+
+__all__ = (
+    'NetBoxAPIHyperlinkedIdentityField',
+    'NetBoxURLHyperlinkedIdentityField',
+)
+
+
+class BaseNetBoxHyperlinkedIdentityField(serializers.HyperlinkedIdentityField):
+    """
+    Overrides HyperlinkedIdentityField to use standard NetBox view naming
+    instead of passing in the view_name.  Initialize with a blank view_name
+    and it will get replaced in the get_url call.  Derived classes must
+    define a get_view_name.
+    """
+    def __init__(self, *args, **kwargs):
+        super().__init__(view_name="", *args, **kwargs)
+
+    def get_url(self, obj, view_name, request, format):
+        """
+        Given an object, return the URL that hyperlinks to the object.
+
+        May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
+        attributes are not configured to correctly match the URL conf.
+        """
+        # Unsaved objects will not yet have a valid URL.
+        if hasattr(obj, 'pk') and obj.pk in (None, ''):
+            return None
+
+        lookup_value = getattr(obj, self.lookup_field)
+        kwargs = {self.lookup_url_kwarg: lookup_value}
+
+        model_name = self.parent.Meta.model._meta.model_name
+        app_name = self.parent.Meta.model._meta.app_label
+        view_name = self.get_view_name(app_name, model_name)
+        return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
+
+    def get_view_name(self, app_name, model_name):
+        raise NotImplementedError(_('{class_name} must implement get_view_name()').format(
+            class_name=self.__class__.__name__
+        ))
+
+
+class NetBoxAPIHyperlinkedIdentityField(BaseNetBoxHyperlinkedIdentityField):
+
+    def get_view_name(self, app_name, model_name):
+        return f'{app_name}-api:{model_name}-detail'
+
+
+class NetBoxURLHyperlinkedIdentityField(BaseNetBoxHyperlinkedIdentityField):
+
+    def get_view_name(self, app_name, model_name):
+        return f'{app_name}:{model_name}'

+ 1 - 2
netbox/netbox/api/serializers/nested.py

@@ -23,8 +23,7 @@ class WritableNestedSerializer(BaseModelSerializer):
 
 
 # Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
 # Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
 class NestedTagSerializer(WritableNestedSerializer):
 class NestedTagSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='extras-api:tag-detail')
 
 
     class Meta:
     class Meta:
         model = Tag
         model = Tag
-        fields = ['id', 'url', 'display', 'name', 'slug', 'color']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'color']

+ 5 - 11
netbox/tenancy/api/nested_serializers.py

@@ -22,21 +22,19 @@ __all__ = [
     exclude_fields=('tenant_count',),
     exclude_fields=('tenant_count',),
 )
 )
 class NestedTenantGroupSerializer(WritableNestedSerializer):
 class NestedTenantGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
     tenant_count = serializers.IntegerField(read_only=True)
     tenant_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = TenantGroup
         model = TenantGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'tenant_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'tenant_count', '_depth']
 
 
 
 
 class NestedTenantSerializer(WritableNestedSerializer):
 class NestedTenantSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
 
 
     class Meta:
     class Meta:
         model = Tenant
         model = Tenant
-        fields = ['id', 'url', 'display', 'name', 'slug']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug']
 
 
 
 
 #
 #
@@ -47,33 +45,29 @@ class NestedTenantSerializer(WritableNestedSerializer):
     exclude_fields=('contact_count',),
     exclude_fields=('contact_count',),
 )
 )
 class NestedContactGroupSerializer(WritableNestedSerializer):
 class NestedContactGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactgroup-detail')
     contact_count = serializers.IntegerField(read_only=True)
     contact_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = ContactGroup
         model = ContactGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'contact_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'contact_count', '_depth']
 
 
 
 
 class NestedContactRoleSerializer(WritableNestedSerializer):
 class NestedContactRoleSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactrole-detail')
 
 
     class Meta:
     class Meta:
         model = ContactRole
         model = ContactRole
-        fields = ['id', 'url', 'display', 'name', 'slug']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug']
 
 
 
 
 class NestedContactSerializer(WritableNestedSerializer):
 class NestedContactSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contact-detail')
 
 
     class Meta:
     class Meta:
         model = Contact
         model = Contact
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedContactAssignmentSerializer(WritableNestedSerializer):
 class NestedContactAssignmentSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactassignment-detail')
     contact = NestedContactSerializer()
     contact = NestedContactSerializer()
     role = NestedContactRoleSerializer
     role = NestedContactRoleSerializer
 
 

+ 8 - 11
netbox/tenancy/api/serializers_/contacts.py

@@ -19,45 +19,42 @@ __all__ = (
 
 
 
 
 class ContactGroupSerializer(NestedGroupModelSerializer):
 class ContactGroupSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactgroup-detail')
     parent = NestedContactGroupSerializer(required=False, allow_null=True, default=None)
     parent = NestedContactGroupSerializer(required=False, allow_null=True, default=None)
     contact_count = serializers.IntegerField(read_only=True, default=0)
     contact_count = serializers.IntegerField(read_only=True, default=0)
 
 
     class Meta:
     class Meta:
         model = ContactGroup
         model = ContactGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'contact_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'contact_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'contact_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'contact_count', '_depth')
 
 
 
 
 class ContactRoleSerializer(NetBoxModelSerializer):
 class ContactRoleSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactrole-detail')
 
 
     class Meta:
     class Meta:
         model = ContactRole
         model = ContactRole
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')
 
 
 
 
 class ContactSerializer(NetBoxModelSerializer):
 class ContactSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contact-detail')
     group = ContactGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     group = ContactGroupSerializer(nested=True, required=False, allow_null=True, default=None)
 
 
     class Meta:
     class Meta:
         model = Contact
         model = Contact
         fields = [
         fields = [
-            'id', 'url', 'display', 'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description',
-            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'group', 'name', 'title', 'phone', 'email', 'address', 'link',
+            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class ContactAssignmentSerializer(NetBoxModelSerializer):
 class ContactAssignmentSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactassignment-detail')
     object_type = ContentTypeField(
     object_type = ContentTypeField(
         queryset=ContentType.objects.all()
         queryset=ContentType.objects.all()
     )
     )
@@ -69,8 +66,8 @@ class ContactAssignmentSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ContactAssignment
         model = ContactAssignment
         fields = [
         fields = [
-            'id', 'url', 'display', 'object_type', 'object_id', 'object', 'contact', 'role', 'priority', 'tags',
-            'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display', 'object_type', 'object_id', 'object', 'contact', 'role', 'priority',
+            'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'contact', 'role', 'priority')
         brief_fields = ('id', 'url', 'display', 'contact', 'role', 'priority')
 
 

+ 6 - 7
netbox/tenancy/api/serializers_/tenants.py

@@ -12,21 +12,19 @@ __all__ = (
 
 
 
 
 class TenantGroupSerializer(NestedGroupModelSerializer):
 class TenantGroupSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
     parent = NestedTenantGroupSerializer(required=False, allow_null=True)
     parent = NestedTenantGroupSerializer(required=False, allow_null=True)
     tenant_count = serializers.IntegerField(read_only=True, default=0)
     tenant_count = serializers.IntegerField(read_only=True, default=0)
 
 
     class Meta:
     class Meta:
         model = TenantGroup
         model = TenantGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'tenant_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'tenant_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tenant_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tenant_count', '_depth')
 
 
 
 
 class TenantSerializer(NetBoxModelSerializer):
 class TenantSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenant-detail')
     group = TenantGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     group = TenantGroupSerializer(nested=True, required=False, allow_null=True, default=None)
 
 
     # Related object counts
     # Related object counts
@@ -44,8 +42,9 @@ class TenantSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Tenant
         model = Tenant
         fields = [
         fields = [
-            'id', 'url', 'display', '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',
+            'id', 'url', 'display_url', 'display', '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',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')

+ 6 - 8
netbox/users/api/nested_serializers.py

@@ -17,19 +17,17 @@ __all__ = [
 
 
 
 
 class NestedGroupSerializer(WritableNestedSerializer):
 class NestedGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')
 
 
     class Meta:
     class Meta:
         model = Group
         model = Group
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedUserSerializer(WritableNestedSerializer):
 class NestedUserSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')
 
 
     class Meta:
     class Meta:
         model = get_user_model()
         model = get_user_model()
-        fields = ['id', 'url', 'display', 'username']
+        fields = ['id', 'url', 'display_url', 'display', 'username']
 
 
     @extend_schema_field(OpenApiTypes.STR)
     @extend_schema_field(OpenApiTypes.STR)
     def get_display(self, obj):
     def get_display(self, obj):
@@ -39,15 +37,13 @@ class NestedUserSerializer(WritableNestedSerializer):
 
 
 
 
 class NestedTokenSerializer(WritableNestedSerializer):
 class NestedTokenSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:token-detail')
 
 
     class Meta:
     class Meta:
         model = Token
         model = Token
-        fields = ['id', 'url', 'display', 'key', 'write_enabled']
+        fields = ['id', 'url', 'display_url', 'display', 'key', 'write_enabled']
 
 
 
 
 class NestedObjectPermissionSerializer(WritableNestedSerializer):
 class NestedObjectPermissionSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
         many=True
         many=True
@@ -57,7 +53,9 @@ class NestedObjectPermissionSerializer(WritableNestedSerializer):
 
 
     class Meta:
     class Meta:
         model = ObjectPermission
         model = ObjectPermission
-        fields = ['id', 'url', 'display', 'name', 'enabled', 'object_types', 'groups', 'users', 'actions']
+        fields = [
+            'id', 'url', 'display_url', 'display', 'name', 'enabled', 'object_types', 'groups', 'users', 'actions'
+        ]
 
 
     @extend_schema_field(serializers.ListField)
     @extend_schema_field(serializers.ListField)
     def get_groups(self, obj):
     def get_groups(self, obj):

+ 2 - 3
netbox/users/api/serializers_/permissions.py

@@ -12,7 +12,6 @@ __all__ = (
 
 
 
 
 class ObjectPermissionSerializer(ValidatedModelSerializer):
 class ObjectPermissionSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail')
     object_types = ContentTypeField(
     object_types = ContentTypeField(
         queryset=ObjectType.objects.all(),
         queryset=ObjectType.objects.all(),
         many=True
         many=True
@@ -35,8 +34,8 @@ class ObjectPermissionSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = ObjectPermission
         model = ObjectPermission
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'enabled', 'object_types', 'actions', 'constraints',
-            'groups', 'users',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'enabled', 'object_types', 'actions',
+            'constraints', 'groups', 'users',
         )
         )
         brief_fields = (
         brief_fields = (
             'id', 'url', 'display', 'name', 'description', 'enabled', 'object_types', 'actions',
             'id', 'url', 'display', 'name', 'description', 'enabled', 'object_types', 'actions',

+ 4 - 5
netbox/users/api/serializers_/tokens.py

@@ -15,7 +15,6 @@ __all__ = (
 
 
 
 
 class TokenSerializer(ValidatedModelSerializer):
 class TokenSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:token-detail')
     key = serializers.CharField(
     key = serializers.CharField(
         min_length=40,
         min_length=40,
         max_length=40,
         max_length=40,
@@ -34,8 +33,8 @@ class TokenSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = Token
         model = Token
         fields = (
         fields = (
-            'id', 'url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled', 'description',
-            'allowed_ips',
+            'id', 'url', 'display_url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled',
+            'description', 'allowed_ips',
         )
         )
         brief_fields = ('id', 'url', 'display', 'key', 'write_enabled', 'description')
         brief_fields = ('id', 'url', 'display', 'key', 'write_enabled', 'description')
 
 
@@ -76,8 +75,8 @@ class TokenProvisionSerializer(TokenSerializer):
     class Meta:
     class Meta:
         model = Token
         model = Token
         fields = (
         fields = (
-            'id', 'url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled', 'description',
-            'allowed_ips', 'username', 'password',
+            'id', 'url', 'display_url', 'display', 'user', 'created', 'expires', 'last_used', 'key', 'write_enabled',
+            'description', 'allowed_ips', 'username', 'password',
         )
         )
 
 
     def validate(self, data):
     def validate(self, data):

+ 3 - 5
netbox/users/api/serializers_/users.py

@@ -15,7 +15,6 @@ __all__ = (
 
 
 
 
 class GroupSerializer(ValidatedModelSerializer):
 class GroupSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail')
     user_count = serializers.IntegerField(read_only=True)
     user_count = serializers.IntegerField(read_only=True)
     permissions = SerializedPKRelatedField(
     permissions = SerializedPKRelatedField(
         source='object_permissions',
         source='object_permissions',
@@ -28,12 +27,11 @@ class GroupSerializer(ValidatedModelSerializer):
 
 
     class Meta:
     class Meta:
         model = Group
         model = Group
-        fields = ('id', 'url', 'display', 'name', 'description', 'permissions', 'user_count')
+        fields = ('id', 'url', 'display_url', 'display', 'name', 'description', 'permissions', 'user_count')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class UserSerializer(ValidatedModelSerializer):
 class UserSerializer(ValidatedModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail')
     groups = SerializedPKRelatedField(
     groups = SerializedPKRelatedField(
         queryset=Group.objects.all(),
         queryset=Group.objects.all(),
         serializer=GroupSerializer,
         serializer=GroupSerializer,
@@ -53,8 +51,8 @@ class UserSerializer(ValidatedModelSerializer):
     class Meta:
     class Meta:
         model = get_user_model()
         model = get_user_model()
         fields = (
         fields = (
-            'id', 'url', 'display', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active',
-            'date_joined', 'last_login', 'groups', 'permissions',
+            'id', 'url', 'display_url', 'display', 'username', 'password', 'first_name', 'last_name', 'email',
+            'is_staff', 'is_active', 'date_joined', 'last_login', 'groups', 'permissions',
         )
         )
         brief_fields = ('id', 'url', 'display', 'username')
         brief_fields = ('id', 'url', 'display', 'username')
         extra_kwargs = {
         extra_kwargs = {

+ 6 - 12
netbox/virtualization/api/nested_serializers.py

@@ -23,36 +23,33 @@ __all__ = [
     exclude_fields=('cluster_count',),
     exclude_fields=('cluster_count',),
 )
 )
 class NestedClusterTypeSerializer(WritableNestedSerializer):
 class NestedClusterTypeSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail')
     cluster_count = RelatedObjectCountField('clusters')
     cluster_count = RelatedObjectCountField('clusters')
 
 
     class Meta:
     class Meta:
         model = ClusterType
         model = ClusterType
-        fields = ['id', 'url', 'display', 'name', 'slug', 'cluster_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'cluster_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('cluster_count',),
     exclude_fields=('cluster_count',),
 )
 )
 class NestedClusterGroupSerializer(WritableNestedSerializer):
 class NestedClusterGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail')
     cluster_count = RelatedObjectCountField('clusters')
     cluster_count = RelatedObjectCountField('clusters')
 
 
     class Meta:
     class Meta:
         model = ClusterGroup
         model = ClusterGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'cluster_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'cluster_count']
 
 
 
 
 @extend_schema_serializer(
 @extend_schema_serializer(
     exclude_fields=('virtualmachine_count',),
     exclude_fields=('virtualmachine_count',),
 )
 )
 class NestedClusterSerializer(WritableNestedSerializer):
 class NestedClusterSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
     virtualmachine_count = RelatedObjectCountField('virtual_machines')
 
 
     class Meta:
     class Meta:
         model = Cluster
         model = Cluster
-        fields = ['id', 'url', 'display', 'name', 'virtualmachine_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'virtualmachine_count']
 
 
 
 
 #
 #
@@ -60,26 +57,23 @@ class NestedClusterSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedVirtualMachineSerializer(WritableNestedSerializer):
 class NestedVirtualMachineSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail')
 
 
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
-        fields = ['id', 'url', 'display', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'name']
 
 
 
 
 class NestedVMInterfaceSerializer(WritableNestedSerializer):
 class NestedVMInterfaceSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
     virtual_machine = NestedVirtualMachineSerializer(read_only=True)
     virtual_machine = NestedVirtualMachineSerializer(read_only=True)
 
 
     class Meta:
     class Meta:
         model = VMInterface
         model = VMInterface
-        fields = ['id', 'url', 'display', 'virtual_machine', 'name']
+        fields = ['id', 'url', 'display_url', 'display', 'virtual_machine', 'name']
 
 
 
 
 class NestedVirtualDiskSerializer(WritableNestedSerializer):
 class NestedVirtualDiskSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualdisk-detail')
     virtual_machine = NestedVirtualMachineSerializer(read_only=True)
     virtual_machine = NestedVirtualMachineSerializer(read_only=True)
 
 
     class Meta:
     class Meta:
         model = VirtualDisk
         model = VirtualDisk
-        fields = ['id', 'url', 'display', 'virtual_machine', 'name', 'size']
+        fields = ['id', 'url', 'display_url', 'display', 'virtual_machine', 'name', 'size']

+ 7 - 9
netbox/virtualization/api/serializers_/clusters.py

@@ -15,7 +15,6 @@ __all__ = (
 
 
 
 
 class ClusterTypeSerializer(NetBoxModelSerializer):
 class ClusterTypeSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustertype-detail')
 
 
     # Related object counts
     # Related object counts
     cluster_count = RelatedObjectCountField('clusters')
     cluster_count = RelatedObjectCountField('clusters')
@@ -23,14 +22,13 @@ class ClusterTypeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ClusterType
         model = ClusterType
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
-            'cluster_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'cluster_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'cluster_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'cluster_count')
 
 
 
 
 class ClusterGroupSerializer(NetBoxModelSerializer):
 class ClusterGroupSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:clustergroup-detail')
 
 
     # Related object counts
     # Related object counts
     cluster_count = RelatedObjectCountField('clusters')
     cluster_count = RelatedObjectCountField('clusters')
@@ -38,14 +36,13 @@ class ClusterGroupSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = ClusterGroup
         model = ClusterGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
-            'cluster_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'cluster_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'cluster_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'cluster_count')
 
 
 
 
 class ClusterSerializer(NetBoxModelSerializer):
 class ClusterSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
     type = ClusterTypeSerializer(nested=True)
     type = ClusterTypeSerializer(nested=True)
     group = ClusterGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     group = ClusterGroupSerializer(nested=True, required=False, allow_null=True, default=None)
     status = ChoiceField(choices=ClusterStatusChoices, required=False)
     status = ChoiceField(choices=ClusterStatusChoices, required=False)
@@ -59,7 +56,8 @@ class ClusterSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Cluster
         model = Cluster
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'type', 'group', 'status', 'tenant', 'site', 'description', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
+            'id', 'url', 'display_url', 'display', 'name', 'type', 'group', 'status', 'tenant', 'site',
+            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
+            'virtualmachine_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'virtualmachine_count')
         brief_fields = ('id', 'url', 'display', 'name', 'description', 'virtualmachine_count')

+ 7 - 10
netbox/virtualization/api/serializers_/virtualmachines.py

@@ -29,7 +29,6 @@ __all__ = (
 
 
 
 
 class VirtualMachineSerializer(NetBoxModelSerializer):
 class VirtualMachineSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail')
     status = ChoiceField(choices=VirtualMachineStatusChoices, required=False)
     status = ChoiceField(choices=VirtualMachineStatusChoices, required=False)
     site = SiteSerializer(nested=True, required=False, allow_null=True, default=None)
     site = SiteSerializer(nested=True, required=False, allow_null=True, default=None)
     cluster = ClusterSerializer(nested=True, required=False, allow_null=True, default=None)
     cluster = ClusterSerializer(nested=True, required=False, allow_null=True, default=None)
@@ -49,7 +48,7 @@ class VirtualMachineSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', 'tenant',
+            'id', 'url', 'display_url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', 'tenant',
             'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description',
             'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description',
             'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
             'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
             'interface_count', 'virtual_disk_count',
             'interface_count', 'virtual_disk_count',
@@ -62,7 +61,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
 
 
     class Meta(VirtualMachineSerializer.Meta):
     class Meta(VirtualMachineSerializer.Meta):
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', 'tenant',
+            'id', 'url', 'display_url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', 'tenant',
             'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description',
             'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description',
             'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created',
             'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created',
             'last_updated', 'interface_count', 'virtual_disk_count',
             'last_updated', 'interface_count', 'virtual_disk_count',
@@ -78,7 +77,6 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
 #
 #
 
 
 class VMInterfaceSerializer(NetBoxModelSerializer):
 class VMInterfaceSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
     virtual_machine = VirtualMachineSerializer(nested=True)
     virtual_machine = VirtualMachineSerializer(nested=True)
     parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
     parent = NestedVMInterfaceSerializer(required=False, allow_null=True)
     bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
     bridge = NestedVMInterfaceSerializer(required=False, allow_null=True)
@@ -104,9 +102,9 @@ class VMInterfaceSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = VMInterface
         model = VMInterface
         fields = [
         fields = [
-            'id', 'url', 'display', 'virtual_machine', 'name', 'enabled', 'parent', 'bridge', 'mtu', 'mac_address',
-            'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'vrf', 'l2vpn_termination', 'tags', 'custom_fields',
-            'created', 'last_updated', 'count_ipaddresses', 'count_fhrp_groups',
+            'id', 'url', 'display_url', 'display', 'virtual_machine', 'name', 'enabled', 'parent', 'bridge', 'mtu',
+            'mac_address', 'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'vrf', 'l2vpn_termination',
+            'tags', 'custom_fields', 'created', 'last_updated', 'count_ipaddresses', 'count_fhrp_groups',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'virtual_machine', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'virtual_machine', 'name', 'description')
 
 
@@ -129,13 +127,12 @@ class VMInterfaceSerializer(NetBoxModelSerializer):
 #
 #
 
 
 class VirtualDiskSerializer(NetBoxModelSerializer):
 class VirtualDiskSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualdisk-detail')
     virtual_machine = VirtualMachineSerializer(nested=True)
     virtual_machine = VirtualMachineSerializer(nested=True)
 
 
     class Meta:
     class Meta:
         model = VirtualDisk
         model = VirtualDisk
         fields = [
         fields = [
-            'id', 'url', 'display', 'virtual_machine', 'name', 'description', 'size', 'tags', 'custom_fields',
-            'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'virtual_machine', 'name', 'description', 'size', 'tags',
+            'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'virtual_machine', 'name', 'description', 'size')
         brief_fields = ('id', 'url', 'display', 'virtual_machine', 'name', 'description', 'size')

+ 10 - 34
netbox/vpn/api/nested_serializers.py

@@ -23,82 +23,60 @@ __all__ = (
     exclude_fields=('tunnel_count',),
     exclude_fields=('tunnel_count',),
 )
 )
 class NestedTunnelGroupSerializer(WritableNestedSerializer):
 class NestedTunnelGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
     tunnel_count = RelatedObjectCountField('tunnels')
     tunnel_count = RelatedObjectCountField('tunnels')
 
 
     class Meta:
     class Meta:
         model = models.TunnelGroup
         model = models.TunnelGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'tunnel_count']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'tunnel_count']
 
 
 
 
 class NestedTunnelSerializer(WritableNestedSerializer):
 class NestedTunnelSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:tunnel-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.Tunnel
         model = models.Tunnel
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 class NestedTunnelTerminationSerializer(WritableNestedSerializer):
 class NestedTunnelTerminationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:tunneltermination-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.TunnelTermination
         model = models.TunnelTermination
-        fields = ('id', 'url', 'display')
+        fields = ('id', 'url', 'display_url', 'display')
 
 
 
 
 class NestedIKEProposalSerializer(WritableNestedSerializer):
 class NestedIKEProposalSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ikeproposal-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.IKEProposal
         model = models.IKEProposal
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 class NestedIKEPolicySerializer(WritableNestedSerializer):
 class NestedIKEPolicySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ikepolicy-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.IKEPolicy
         model = models.IKEPolicy
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 class NestedIPSecProposalSerializer(WritableNestedSerializer):
 class NestedIPSecProposalSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecproposal-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.IPSecProposal
         model = models.IPSecProposal
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 class NestedIPSecPolicySerializer(WritableNestedSerializer):
 class NestedIPSecPolicySerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecpolicy-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.IPSecPolicy
         model = models.IPSecPolicy
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 class NestedIPSecProfileSerializer(WritableNestedSerializer):
 class NestedIPSecProfileSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecprofile-detail'
-    )
 
 
     class Meta:
     class Meta:
         model = models.IPSecProfile
         model = models.IPSecProfile
-        fields = ('id', 'url', 'display', 'name')
+        fields = ('id', 'url', 'display_url', 'display', 'name')
 
 
 
 
 #
 #
@@ -106,21 +84,19 @@ class NestedIPSecProfileSerializer(WritableNestedSerializer):
 #
 #
 
 
 class NestedL2VPNSerializer(WritableNestedSerializer):
 class NestedL2VPNSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpn-detail')
 
 
     class Meta:
     class Meta:
         model = models.L2VPN
         model = models.L2VPN
         fields = [
         fields = [
-            'id', 'url', 'display', 'identifier', 'name', 'slug', 'type'
+            'id', 'url', 'display', 'display_url', 'identifier', 'name', 'slug', 'type'
         ]
         ]
 
 
 
 
 class NestedL2VPNTerminationSerializer(WritableNestedSerializer):
 class NestedL2VPNTerminationSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpntermination-detail')
     l2vpn = NestedL2VPNSerializer()
     l2vpn = NestedL2VPNSerializer()
 
 
     class Meta:
     class Meta:
         model = models.L2VPNTermination
         model = models.L2VPNTermination
         fields = [
         fields = [
-            'id', 'url', 'display', 'l2vpn'
+            'id', 'url', 'display_url', 'display', 'l2vpn'
         ]
         ]

+ 10 - 25
netbox/vpn/api/serializers_/crypto.py

@@ -15,9 +15,6 @@ __all__ = (
 
 
 
 
 class IKEProposalSerializer(NetBoxModelSerializer):
 class IKEProposalSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ikeproposal-detail'
-    )
     authentication_method = ChoiceField(
     authentication_method = ChoiceField(
         choices=AuthenticationMethodChoices
         choices=AuthenticationMethodChoices
     )
     )
@@ -34,17 +31,14 @@ class IKEProposalSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IKEProposal
         model = IKEProposal
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'authentication_method', 'encryption_algorithm',
-            'authentication_algorithm', 'group', 'sa_lifetime', 'comments', 'tags', 'custom_fields', 'created',
-            'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'authentication_method',
+            'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime', 'comments', 'tags',
+            'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class IKEPolicySerializer(NetBoxModelSerializer):
 class IKEPolicySerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ikepolicy-detail'
-    )
     version = ChoiceField(
     version = ChoiceField(
         choices=IKEVersionChoices
         choices=IKEVersionChoices
     )
     )
@@ -62,16 +56,13 @@ class IKEPolicySerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IKEPolicy
         model = IKEPolicy
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'version', 'mode', 'proposals', 'preshared_key', 'comments',
-            'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'version', 'mode', 'proposals',
+            'preshared_key', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class IPSecProposalSerializer(NetBoxModelSerializer):
 class IPSecProposalSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecproposal-detail'
-    )
     encryption_algorithm = ChoiceField(
     encryption_algorithm = ChoiceField(
         choices=EncryptionAlgorithmChoices
         choices=EncryptionAlgorithmChoices
     )
     )
@@ -82,16 +73,13 @@ class IPSecProposalSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IPSecProposal
         model = IPSecProposal
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'encryption_algorithm', 'authentication_algorithm',
-            'sa_lifetime_seconds', 'sa_lifetime_data', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'encryption_algorithm',
+            'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class IPSecPolicySerializer(NetBoxModelSerializer):
 class IPSecPolicySerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecpolicy-detail'
-    )
     proposals = SerializedPKRelatedField(
     proposals = SerializedPKRelatedField(
         queryset=IPSecProposal.objects.all(),
         queryset=IPSecProposal.objects.all(),
         serializer=IPSecProposalSerializer,
         serializer=IPSecProposalSerializer,
@@ -107,16 +95,13 @@ class IPSecPolicySerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IPSecPolicy
         model = IPSecPolicy
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'proposals', 'pfs_group', 'comments', 'tags',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'proposals', 'pfs_group', 'comments', 'tags',
             'custom_fields', 'created', 'last_updated',
             'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class IPSecProfileSerializer(NetBoxModelSerializer):
 class IPSecProfileSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:ipsecprofile-detail'
-    )
     mode = ChoiceField(
     mode = ChoiceField(
         choices=IPSecModeChoices
         choices=IPSecModeChoices
     )
     )
@@ -130,7 +115,7 @@ class IPSecProfileSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = IPSecProfile
         model = IPSecProfile
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'description', 'mode', 'ike_policy', 'ipsec_policy', 'comments', 'tags',
-            'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'name', 'description', 'mode', 'ike_policy', 'ipsec_policy',
+            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')

+ 3 - 5
netbox/vpn/api/serializers_/l2vpn.py

@@ -18,7 +18,6 @@ __all__ = (
 
 
 
 
 class L2VPNSerializer(NetBoxModelSerializer):
 class L2VPNSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpn-detail')
     type = ChoiceField(choices=L2VPNTypeChoices, required=False)
     type = ChoiceField(choices=L2VPNTypeChoices, required=False)
     import_targets = SerializedPKRelatedField(
     import_targets = SerializedPKRelatedField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
@@ -39,14 +38,13 @@ class L2VPNSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = L2VPN
         model = L2VPN
         fields = [
         fields = [
-            'id', 'url', 'display', 'identifier', 'name', 'slug', 'type', 'import_targets', 'export_targets',
-            'description', 'comments', 'tenant', 'tags', 'custom_fields', 'created', 'last_updated'
+            'id', 'url', 'display_url', 'display', 'identifier', 'name', 'slug', 'type', 'import_targets',
+            'export_targets', 'description', 'comments', 'tenant', 'tags', 'custom_fields', 'created', 'last_updated'
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'identifier', 'name', 'slug', 'type', 'description')
         brief_fields = ('id', 'url', 'display', 'identifier', 'name', 'slug', 'type', 'description')
 
 
 
 
 class L2VPNTerminationSerializer(NetBoxModelSerializer):
 class L2VPNTerminationSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:l2vpntermination-detail')
     l2vpn = L2VPNSerializer(
     l2vpn = L2VPNSerializer(
         nested=True
         nested=True
     )
     )
@@ -58,7 +56,7 @@ class L2VPNTerminationSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = L2VPNTermination
         model = L2VPNTermination
         fields = [
         fields = [
-            'id', 'url', 'display', 'l2vpn', 'assigned_object_type', 'assigned_object_id',
+            'id', 'url', 'display_url', 'display', 'l2vpn', 'assigned_object_type', 'assigned_object_id',
             'assigned_object', 'tags', 'custom_fields', 'created', 'last_updated'
             'assigned_object', 'tags', 'custom_fields', 'created', 'last_updated'
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'l2vpn')
         brief_fields = ('id', 'url', 'display', 'l2vpn')

+ 7 - 13
netbox/vpn/api/serializers_/tunnels.py

@@ -23,7 +23,6 @@ __all__ = (
 #
 #
 
 
 class TunnelGroupSerializer(NetBoxModelSerializer):
 class TunnelGroupSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='vpn-api:tunnelgroup-detail')
 
 
     # Related object counts
     # Related object counts
     tunnel_count = RelatedObjectCountField('tunnels')
     tunnel_count = RelatedObjectCountField('tunnels')
@@ -31,16 +30,13 @@ class TunnelGroupSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = TunnelGroup
         model = TunnelGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
-            'tunnel_count',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'tunnel_count',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tunnel_count')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'tunnel_count')
 
 
 
 
 class TunnelSerializer(NetBoxModelSerializer):
 class TunnelSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:tunnel-detail'
-    )
     status = ChoiceField(
     status = ChoiceField(
         choices=TunnelStatusChoices
         choices=TunnelStatusChoices
     )
     )
@@ -70,16 +66,14 @@ class TunnelSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = Tunnel
         model = Tunnel
         fields = (
         fields = (
-            'id', 'url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile', 'tenant', 'tunnel_id',
-            'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'terminations_count',
+            'id', 'url', 'display_url', 'display', 'name', 'status', 'group', 'encapsulation', 'ipsec_profile',
+            'tenant', 'tunnel_id', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'terminations_count',
         )
         )
         brief_fields = ('id', 'url', 'display', 'name', 'description')
         brief_fields = ('id', 'url', 'display', 'name', 'description')
 
 
 
 
 class TunnelTerminationSerializer(NetBoxModelSerializer):
 class TunnelTerminationSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(
-        view_name='vpn-api:tunneltermination-detail'
-    )
     tunnel = TunnelSerializer(
     tunnel = TunnelSerializer(
         nested=True
         nested=True
     )
     )
@@ -101,8 +95,8 @@ class TunnelTerminationSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = TunnelTermination
         model = TunnelTermination
         fields = (
         fields = (
-            'id', 'url', 'display', 'tunnel', 'role', 'termination_type', 'termination_id', 'termination', 'outside_ip',
-            'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'tunnel', 'role', 'termination_type', 'termination_id',
+            'termination', 'outside_ip', 'tags', 'custom_fields', 'created', 'last_updated',
         )
         )
         brief_fields = ('id', 'url', 'display')
         brief_fields = ('id', 'url', 'display')
 
 

+ 3 - 6
netbox/wireless/api/nested_serializers.py

@@ -15,26 +15,23 @@ __all__ = (
     exclude_fields=('wirelesslan_count',),
     exclude_fields=('wirelesslan_count',),
 )
 )
 class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
 class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslangroup-detail')
     wirelesslan_count = serializers.IntegerField(read_only=True)
     wirelesslan_count = serializers.IntegerField(read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
     _depth = serializers.IntegerField(source='level', read_only=True)
 
 
     class Meta:
     class Meta:
         model = WirelessLANGroup
         model = WirelessLANGroup
-        fields = ['id', 'url', 'display', 'name', 'slug', 'wirelesslan_count', '_depth']
+        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug', 'wirelesslan_count', '_depth']
 
 
 
 
 class NestedWirelessLANSerializer(WritableNestedSerializer):
 class NestedWirelessLANSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
 
 
     class Meta:
     class Meta:
         model = WirelessLAN
         model = WirelessLAN
-        fields = ['id', 'url', 'display', 'ssid']
+        fields = ['id', 'url', 'display_url', 'display', 'ssid']
 
 
 
 
 class NestedWirelessLinkSerializer(WritableNestedSerializer):
 class NestedWirelessLinkSerializer(WritableNestedSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
 
 
     class Meta:
     class Meta:
         model = WirelessLink
         model = WirelessLink
-        fields = ['id', 'url', 'display', 'ssid']
+        fields = ['id', 'url', 'display_url', 'display', 'ssid']

+ 5 - 6
netbox/wireless/api/serializers_/wirelesslans.py

@@ -15,21 +15,19 @@ __all__ = (
 
 
 
 
 class WirelessLANGroupSerializer(NestedGroupModelSerializer):
 class WirelessLANGroupSerializer(NestedGroupModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslangroup-detail')
     parent = NestedWirelessLANGroupSerializer(required=False, allow_null=True, default=None)
     parent = NestedWirelessLANGroupSerializer(required=False, allow_null=True, default=None)
     wirelesslan_count = serializers.IntegerField(read_only=True, default=0)
     wirelesslan_count = serializers.IntegerField(read_only=True, default=0)
 
 
     class Meta:
     class Meta:
         model = WirelessLANGroup
         model = WirelessLANGroup
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
-            'last_updated', 'wirelesslan_count', '_depth',
+            'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
+            'created', 'last_updated', 'wirelesslan_count', '_depth',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'wirelesslan_count', '_depth')
         brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'wirelesslan_count', '_depth')
 
 
 
 
 class WirelessLANSerializer(NetBoxModelSerializer):
 class WirelessLANSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
     group = WirelessLANGroupSerializer(nested=True, required=False, allow_null=True)
     group = WirelessLANGroupSerializer(nested=True, required=False, allow_null=True)
     status = ChoiceField(choices=WirelessLANStatusChoices, required=False, allow_blank=True)
     status = ChoiceField(choices=WirelessLANStatusChoices, required=False, allow_blank=True)
     vlan = VLANSerializer(nested=True, required=False, allow_null=True)
     vlan = VLANSerializer(nested=True, required=False, allow_null=True)
@@ -40,7 +38,8 @@ class WirelessLANSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = WirelessLAN
         model = WirelessLAN
         fields = [
         fields = [
-            'id', 'url', 'display', 'ssid', 'description', 'group', 'status', 'vlan', 'tenant', 'auth_type',
-            'auth_cipher', 'auth_psk', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'ssid', 'description', 'group', 'status', 'vlan', 'tenant',
+            'auth_type', 'auth_cipher', 'auth_psk', 'description', 'comments', 'tags', 'custom_fields',
+            'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'ssid', 'description')
         brief_fields = ('id', 'url', 'display', 'ssid', 'description')

+ 3 - 4
netbox/wireless/api/serializers_/wirelesslinks.py

@@ -14,7 +14,6 @@ __all__ = (
 
 
 
 
 class WirelessLinkSerializer(NetBoxModelSerializer):
 class WirelessLinkSerializer(NetBoxModelSerializer):
-    url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail')
     status = ChoiceField(choices=LinkStatusChoices, required=False)
     status = ChoiceField(choices=LinkStatusChoices, required=False)
     interface_a = InterfaceSerializer(nested=True)
     interface_a = InterfaceSerializer(nested=True)
     interface_b = InterfaceSerializer(nested=True)
     interface_b = InterfaceSerializer(nested=True)
@@ -26,8 +25,8 @@ class WirelessLinkSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = WirelessLink
         model = WirelessLink
         fields = [
         fields = [
-            'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'tenant', 'auth_type',
-            'auth_cipher', 'auth_psk', 'distance', 'distance_unit', 'description', 'comments', 'tags', 'custom_fields',
-            'created', 'last_updated',
+            'id', 'url', 'display_url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'tenant',
+            'auth_type', 'auth_cipher', 'auth_psk', 'distance', 'distance_unit', 'description',
+            'comments', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
         ]
         brief_fields = ('id', 'url', 'display', 'ssid', 'description')
         brief_fields = ('id', 'url', 'display', 'ssid', 'description')