Jelajahi Sumber

Closes #5873: Use numeric IDs in all object URLs

Jeremy Stretch 5 tahun lalu
induk
melakukan
6a9b50f95d
37 mengubah file dengan 97 tambahan dan 126 penghapusan
  1. 1 0
      docs/release-notes/version-2.11.md
  2. 1 1
      netbox/circuits/models.py
  3. 3 4
      netbox/circuits/tables.py
  4. 7 7
      netbox/circuits/urls.py
  5. 1 1
      netbox/dcim/models/sites.py
  6. 2 2
      netbox/dcim/tables/devices.py
  7. 1 1
      netbox/dcim/tables/devicetypes.py
  8. 2 3
      netbox/dcim/tables/power.py
  9. 2 4
      netbox/dcim/tables/racks.py
  10. 13 13
      netbox/dcim/urls.py
  11. 1 1
      netbox/extras/tables.py
  12. 3 3
      netbox/extras/urls.py
  13. 8 10
      netbox/ipam/tables.py
  14. 6 6
      netbox/ipam/urls.py
  15. 1 1
      netbox/secrets/tables.py
  16. 3 3
      netbox/secrets/urls.py
  17. 1 1
      netbox/templates/circuits/circuit.html
  18. 1 1
      netbox/templates/circuits/inc/circuit_termination.html
  19. 1 1
      netbox/templates/circuits/provider.html
  20. 2 2
      netbox/templates/dcim/device.html
  21. 2 2
      netbox/templates/dcim/devicetype.html
  22. 1 1
      netbox/templates/dcim/rack.html
  23. 1 1
      netbox/templates/dcim/rackreservation.html
  24. 1 1
      netbox/templates/dcim/site.html
  25. 1 1
      netbox/templates/extras/tag.html
  26. 1 1
      netbox/templates/ipam/prefix.html
  27. 1 1
      netbox/templates/ipam/vlan.html
  28. 1 1
      netbox/templates/ipam/vlangroup_vlans.html
  29. 1 1
      netbox/templates/tenancy/tenant.html
  30. 1 1
      netbox/tenancy/models.py
  31. 2 2
      netbox/tenancy/tables.py
  32. 7 7
      netbox/tenancy/urls.py
  33. 4 6
      netbox/utilities/tables.py
  34. 4 18
      netbox/utilities/templatetags/buttons.py
  35. 1 9
      netbox/utilities/testing/views.py
  36. 2 2
      netbox/virtualization/tables.py
  37. 6 6
      netbox/virtualization/urls.py

+ 1 - 0
docs/release-notes/version-2.11.md

@@ -11,3 +11,4 @@
 ### Other Changes
 
 * [#1638](https://github.com/netbox-community/netbox/issues/1638) - Migrate all primary keys to 64-bit integers
+* [#5873](https://github.com/netbox-community/netbox/issues/5873) - Use numeric IDs in all object URLs

+ 1 - 1
netbox/circuits/models.py

@@ -79,7 +79,7 @@ class Provider(PrimaryModel):
         return self.name
 
     def get_absolute_url(self):
-        return reverse('circuits:provider', args=[self.slug])
+        return reverse('circuits:provider', args=[self.pk])
 
     def to_csv(self):
         return (

+ 3 - 4
netbox/circuits/tables.py

@@ -39,7 +39,7 @@ class CircuitTypeTable(BaseTable):
     circuit_count = tables.Column(
         verbose_name='Circuits'
     )
-    actions = ButtonsColumn(CircuitType, pk_field='slug')
+    actions = ButtonsColumn(CircuitType)
 
     class Meta(BaseTable.Meta):
         model = CircuitType
@@ -56,9 +56,8 @@ class CircuitTable(BaseTable):
     cid = tables.LinkColumn(
         verbose_name='ID'
     )
-    provider = tables.LinkColumn(
-        viewname='circuits:provider',
-        args=[Accessor('provider__slug')]
+    provider = tables.Column(
+        linkify=True
     )
     status = ChoiceFieldColumn()
     tenant = tables.TemplateColumn(

+ 7 - 7
netbox/circuits/urls.py

@@ -14,19 +14,19 @@ urlpatterns = [
     path('providers/import/', views.ProviderBulkImportView.as_view(), name='provider_import'),
     path('providers/edit/', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
     path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
-    path('providers/<slug:slug>/', views.ProviderView.as_view(), name='provider'),
-    path('providers/<slug:slug>/edit/', views.ProviderEditView.as_view(), name='provider_edit'),
-    path('providers/<slug:slug>/delete/', views.ProviderDeleteView.as_view(), name='provider_delete'),
-    path('providers/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
+    path('providers/<int:pk>/', views.ProviderView.as_view(), name='provider'),
+    path('providers/<int:pk>/edit/', views.ProviderEditView.as_view(), name='provider_edit'),
+    path('providers/<int:pk>/delete/', views.ProviderDeleteView.as_view(), name='provider_delete'),
+    path('providers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
 
     # Circuit types
     path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'),
     path('circuit-types/add/', views.CircuitTypeEditView.as_view(), name='circuittype_add'),
     path('circuit-types/import/', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
     path('circuit-types/delete/', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
-    path('circuit-types/<slug:slug>/edit/', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
-    path('circuit-types/<slug:slug>/delete/', views.CircuitTypeDeleteView.as_view(), name='circuittype_delete'),
-    path('circuit-types/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
+    path('circuit-types/<int:pk>/edit/', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
+    path('circuit-types/<int:pk>/delete/', views.CircuitTypeDeleteView.as_view(), name='circuittype_delete'),
+    path('circuit-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
 
     # Circuits
     path('circuits/', views.CircuitListView.as_view(), name='circuit_list'),

+ 1 - 1
netbox/dcim/models/sites.py

@@ -192,7 +192,7 @@ class Site(PrimaryModel):
         return self.name
 
     def get_absolute_url(self):
-        return reverse('dcim:site', args=[self.slug])
+        return reverse('dcim:site', args=[self.pk])
 
     def to_csv(self):
         return (

+ 2 - 2
netbox/dcim/tables/devices.py

@@ -61,7 +61,7 @@ class DeviceRoleTable(BaseTable):
     )
     color = ColorColumn()
     vm_role = BooleanColumn()
-    actions = ButtonsColumn(DeviceRole, pk_field='slug')
+    actions = ButtonsColumn(DeviceRole)
 
     class Meta(BaseTable.Meta):
         model = DeviceRole
@@ -85,7 +85,7 @@ class PlatformTable(BaseTable):
         url_params={'platform': 'slug'},
         verbose_name='VMs'
     )
-    actions = ButtonsColumn(Platform, pk_field='slug')
+    actions = ButtonsColumn(Platform)
 
     class Meta(BaseTable.Meta):
         model = Platform

+ 1 - 1
netbox/dcim/tables/devicetypes.py

@@ -37,7 +37,7 @@ class ManufacturerTable(BaseTable):
         verbose_name='Platforms'
     )
     slug = tables.Column()
-    actions = ButtonsColumn(Manufacturer, pk_field='slug')
+    actions = ButtonsColumn(Manufacturer)
 
     class Meta(BaseTable.Meta):
         model = Manufacturer

+ 2 - 3
netbox/dcim/tables/power.py

@@ -19,9 +19,8 @@ __all__ = (
 class PowerPanelTable(BaseTable):
     pk = ToggleColumn()
     name = tables.LinkColumn()
-    site = tables.LinkColumn(
-        viewname='dcim:site',
-        args=[Accessor('site__slug')]
+    site = tables.Column(
+        linkify=True
     )
     powerfeed_count = LinkedCountColumn(
         viewname='dcim:powerfeed_list',

+ 2 - 4
netbox/dcim/tables/racks.py

@@ -29,10 +29,8 @@ class RackGroupTable(BaseTable):
         orderable=False,
         attrs={'td': {'class': 'text-nowrap'}}
     )
-    site = tables.LinkColumn(
-        viewname='dcim:site',
-        args=[Accessor('site__slug')],
-        verbose_name='Site'
+    site = tables.Column(
+        linkify=True
     )
     rack_count = tables.Column(
         verbose_name='Racks'

+ 13 - 13
netbox/dcim/urls.py

@@ -27,10 +27,10 @@ urlpatterns = [
     path('sites/import/', views.SiteBulkImportView.as_view(), name='site_import'),
     path('sites/edit/', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
     path('sites/delete/', views.SiteBulkDeleteView.as_view(), name='site_bulk_delete'),
-    path('sites/<slug:slug>/', views.SiteView.as_view(), name='site'),
-    path('sites/<slug:slug>/edit/', views.SiteEditView.as_view(), name='site_edit'),
-    path('sites/<slug:slug>/delete/', views.SiteDeleteView.as_view(), name='site_delete'),
-    path('sites/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
+    path('sites/<int:pk>/', views.SiteView.as_view(), name='site'),
+    path('sites/<int:pk>/edit/', views.SiteEditView.as_view(), name='site_edit'),
+    path('sites/<int:pk>/delete/', views.SiteDeleteView.as_view(), name='site_delete'),
+    path('sites/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
     path('sites/<int:object_id>/images/add/', ImageAttachmentEditView.as_view(), name='site_add_image', kwargs={'model': Site}),
 
     # Rack groups
@@ -80,9 +80,9 @@ urlpatterns = [
     path('manufacturers/add/', views.ManufacturerEditView.as_view(), name='manufacturer_add'),
     path('manufacturers/import/', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
     path('manufacturers/delete/', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
-    path('manufacturers/<slug:slug>/edit/', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
-    path('manufacturers/<slug:slug>/delete/', views.ManufacturerDeleteView.as_view(), name='manufacturer_delete'),
-    path('manufacturers/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
+    path('manufacturers/<int:pk>/edit/', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
+    path('manufacturers/<int:pk>/delete/', views.ManufacturerDeleteView.as_view(), name='manufacturer_delete'),
+    path('manufacturers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
 
     # Device types
     path('device-types/', views.DeviceTypeListView.as_view(), name='devicetype_list'),
@@ -164,18 +164,18 @@ urlpatterns = [
     path('device-roles/add/', views.DeviceRoleEditView.as_view(), name='devicerole_add'),
     path('device-roles/import/', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
     path('device-roles/delete/', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
-    path('device-roles/<slug:slug>/edit/', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
-    path('device-roles/<slug:slug>/delete/', views.DeviceRoleDeleteView.as_view(), name='devicerole_delete'),
-    path('device-roles/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
+    path('device-roles/<int:pk>/edit/', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
+    path('device-roles/<int:pk>/delete/', views.DeviceRoleDeleteView.as_view(), name='devicerole_delete'),
+    path('device-roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
 
     # Platforms
     path('platforms/', views.PlatformListView.as_view(), name='platform_list'),
     path('platforms/add/', views.PlatformEditView.as_view(), name='platform_add'),
     path('platforms/import/', views.PlatformBulkImportView.as_view(), name='platform_import'),
     path('platforms/delete/', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
-    path('platforms/<slug:slug>/edit/', views.PlatformEditView.as_view(), name='platform_edit'),
-    path('platforms/<slug:slug>/delete/', views.PlatformDeleteView.as_view(), name='platform_delete'),
-    path('platforms/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
+    path('platforms/<int:pk>/edit/', views.PlatformEditView.as_view(), name='platform_edit'),
+    path('platforms/<int:pk>/delete/', views.PlatformDeleteView.as_view(), name='platform_delete'),
+    path('platforms/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
 
     # Devices
     path('devices/', views.DeviceListView.as_view(), name='device_list'),

+ 1 - 1
netbox/extras/tables.py

@@ -37,7 +37,7 @@ OBJECTCHANGE_REQUEST_ID = """
 class TagTable(BaseTable):
     pk = ToggleColumn()
     color = ColorColumn()
-    actions = ButtonsColumn(Tag, pk_field='slug')
+    actions = ButtonsColumn(Tag)
 
     class Meta(BaseTable.Meta):
         model = Tag

+ 3 - 3
netbox/extras/urls.py

@@ -13,9 +13,9 @@ urlpatterns = [
     path('tags/import/', views.TagBulkImportView.as_view(), name='tag_import'),
     path('tags/edit/', views.TagBulkEditView.as_view(), name='tag_bulk_edit'),
     path('tags/delete/', views.TagBulkDeleteView.as_view(), name='tag_bulk_delete'),
-    path('tags/<str:slug>/edit/', views.TagEditView.as_view(), name='tag_edit'),
-    path('tags/<str:slug>/delete/', views.TagDeleteView.as_view(), name='tag_delete'),
-    path('tags/<str:slug>/changelog/', views.ObjectChangeLogView.as_view(), name='tag_changelog', kwargs={'model': Tag}),
+    path('tags/<int:pk>/edit/', views.TagEditView.as_view(), name='tag_edit'),
+    path('tags/<int:pk>/delete/', views.TagDeleteView.as_view(), name='tag_delete'),
+    path('tags/<int:pk>/changelog/', views.ObjectChangeLogView.as_view(), name='tag_changelog', kwargs={'model': Tag}),
 
     # Config contexts
     path('config-contexts/', views.ConfigContextListView.as_view(), name='configcontext_list'),

+ 8 - 10
netbox/ipam/tables.py

@@ -111,9 +111,9 @@ VLAN_MEMBER_TAGGED = """
 
 TENANT_LINK = """
 {% if record.tenant %}
-    <a href="{% url 'tenancy:tenant' slug=record.tenant.slug %}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
+    <a href="{{ record.tenant.get_absolute_url }}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
 {% elif record.vrf.tenant %}
-    <a href="{% url 'tenancy:tenant' slug=record.vrf.tenant.slug %}" title="{{ record.vrf.tenant.description }}">{{ record.vrf.tenant }}</a>*
+    <a href="{{ record.vrf.tenant.get_absolute_url }}" title="{{ record.vrf.tenant.description }}">{{ record.vrf.tenant }}</a>*
 {% else %}
     &mdash;
 {% endif %}
@@ -191,7 +191,7 @@ class RIRTable(BaseTable):
         url_params={'rir': 'slug'},
         verbose_name='Aggregates'
     )
-    actions = ButtonsColumn(RIR, pk_field='slug')
+    actions = ButtonsColumn(RIR)
 
     class Meta(BaseTable.Meta):
         model = RIR
@@ -254,7 +254,7 @@ class RoleTable(BaseTable):
         url_params={'role': 'slug'},
         verbose_name='VLANs'
     )
-    actions = ButtonsColumn(Role, pk_field='slug')
+    actions = ButtonsColumn(Role)
 
     class Meta(BaseTable.Meta):
         model = Role
@@ -444,9 +444,8 @@ class InterfaceIPAddressTable(BaseTable):
 class VLANGroupTable(BaseTable):
     pk = ToggleColumn()
     name = tables.Column(linkify=True)
-    site = tables.LinkColumn(
-        viewname='dcim:site',
-        args=[Accessor('site__slug')]
+    site = tables.Column(
+        linkify=True
     )
     vlan_count = LinkedCountColumn(
         viewname='ipam:vlan_list',
@@ -474,9 +473,8 @@ class VLANTable(BaseTable):
         template_code=VLAN_LINK,
         verbose_name='ID'
     )
-    site = tables.LinkColumn(
-        viewname='dcim:site',
-        args=[Accessor('site__slug')]
+    site = tables.Column(
+        linkify=True
     )
     group = tables.LinkColumn(
         viewname='ipam:vlangroup_vlans',

+ 6 - 6
netbox/ipam/urls.py

@@ -34,9 +34,9 @@ urlpatterns = [
     path('rirs/add/', views.RIREditView.as_view(), name='rir_add'),
     path('rirs/import/', views.RIRBulkImportView.as_view(), name='rir_import'),
     path('rirs/delete/', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
-    path('rirs/<slug:slug>/edit/', views.RIREditView.as_view(), name='rir_edit'),
-    path('rirs/<slug:slug>/delete/', views.RIRDeleteView.as_view(), name='rir_delete'),
-    path('vrfs/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}),
+    path('rirs/<int:pk>/edit/', views.RIREditView.as_view(), name='rir_edit'),
+    path('rirs/<int:pk>/delete/', views.RIRDeleteView.as_view(), name='rir_delete'),
+    path('rirs/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rir_changelog', kwargs={'model': RIR}),
 
     # Aggregates
     path('aggregates/', views.AggregateListView.as_view(), name='aggregate_list'),
@@ -54,9 +54,9 @@ urlpatterns = [
     path('roles/add/', views.RoleEditView.as_view(), name='role_add'),
     path('roles/import/', views.RoleBulkImportView.as_view(), name='role_import'),
     path('roles/delete/', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
-    path('roles/<slug:slug>/edit/', views.RoleEditView.as_view(), name='role_edit'),
-    path('roles/<slug:slug>/delete/', views.RoleDeleteView.as_view(), name='role_delete'),
-    path('roles/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}),
+    path('roles/<int:pk>/edit/', views.RoleEditView.as_view(), name='role_edit'),
+    path('roles/<int:pk>/delete/', views.RoleDeleteView.as_view(), name='role_delete'),
+    path('roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='role_changelog', kwargs={'model': Role}),
 
     # Prefixes
     path('prefixes/', views.PrefixListView.as_view(), name='prefix_list'),

+ 1 - 1
netbox/secrets/tables.py

@@ -16,7 +16,7 @@ class SecretRoleTable(BaseTable):
         url_params={'role': 'slug'},
         verbose_name='Secrets'
     )
-    actions = ButtonsColumn(SecretRole, pk_field='slug')
+    actions = ButtonsColumn(SecretRole)
 
     class Meta(BaseTable.Meta):
         model = SecretRole

+ 3 - 3
netbox/secrets/urls.py

@@ -12,9 +12,9 @@ urlpatterns = [
     path('secret-roles/add/', views.SecretRoleEditView.as_view(), name='secretrole_add'),
     path('secret-roles/import/', views.SecretRoleBulkImportView.as_view(), name='secretrole_import'),
     path('secret-roles/delete/', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
-    path('secret-roles/<slug:slug>/edit/', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
-    path('secret-roles/<slug:slug>/delete/', views.SecretRoleDeleteView.as_view(), name='secretrole_delete'),
-    path('secret-roles/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}),
+    path('secret-roles/<int:pk>/edit/', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
+    path('secret-roles/<int:pk>/delete/', views.SecretRoleDeleteView.as_view(), name='secretrole_delete'),
+    path('secret-roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='secretrole_changelog', kwargs={'model': SecretRole}),
 
     # Secrets
     path('secrets/', views.SecretListView.as_view(), name='secret_list'),

+ 1 - 1
netbox/templates/circuits/circuit.html

@@ -74,7 +74,7 @@
                 <tr>
                     <td>Provider</td>
                     <td>
-                        <a href="{% url 'circuits:provider' slug=object.provider.slug %}">{{ object.provider }}</a>
+                        <a href="{{ object.provider.get_absolute_url }}">{{ object.provider }}</a>
                     </td>
                 </tr>
                 <tr>

+ 1 - 1
netbox/templates/circuits/inc/circuit_termination.html

@@ -32,7 +32,7 @@
                     {% if termination.site.region %}
                         <a href="{{ termination.site.region.get_absolute_url }}">{{ termination.site.region }}</a> /
                     {% endif %}
-                    <a href="{% url 'dcim:site' slug=termination.site.slug %}">{{ termination.site }}</a>
+                    <a href="{{ termination.site.get_absolute_url }}">{{ termination.site }}</a>
                 </td>
             </tr>
             <tr>

+ 1 - 1
netbox/templates/circuits/provider.html

@@ -51,7 +51,7 @@
         </li>
         {% if perms.extras.view_objectchange %}
             <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
-                <a href="{% url 'circuits:provider_changelog' slug=object.slug %}">Change Log</a>
+                <a href="{% url 'circuits:provider_changelog' pk=object.pk %}">Change Log</a>
             </li>
         {% endif %}
     </ul>

+ 2 - 2
netbox/templates/dcim/device.html

@@ -23,7 +23,7 @@
                                             {% if object.site.region %}
                                                 <a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> /
                                             {% endif %}
-                                            <a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a>
+                                            <a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a>
                                         </td>
                                     </tr>
                                     <tr>
@@ -74,7 +74,7 @@
                                     <tr>
                                         <td>Device Type</td>
                                         <td>
-                                            <span><a href="{% url 'dcim:devicetype' pk=object.device_type.pk %}">{{ object.device_type.display_name }}</a> ({{ object.device_type.u_height }}U)</span>
+                                            <span><a href="{{ object.device_type.get_absolute_url }}">{{ object.device_type.display_name }}</a> ({{ object.device_type.u_height }}U)</span>
                                         </td>
                                     </tr>
                                     <tr>

+ 2 - 2
netbox/templates/dcim/devicetype.html

@@ -55,10 +55,10 @@
             {% clone_button object %}
         {% endif %}
         {% if perms.dcim.change_devicetype %}
-            {% edit_button object use_pk=True %}
+            {% edit_button object %}
         {% endif %}
         {% if perms.dcim.delete_devicetype %}
-            {% delete_button object use_pk=True %}
+            {% delete_button object %}
         {% endif %}
     </div>
     <h1>{{ object.manufacturer }} {{ object.model }}</h1>

+ 1 - 1
netbox/templates/dcim/rack.html

@@ -85,7 +85,7 @@
                         {% if object.site.region %}
                             <a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> /
                         {% endif %}
-                        <a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a>
+                        <a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a>
                     </td>
                 </tr>
                 <tr>

+ 1 - 1
netbox/templates/dcim/rackreservation.html

@@ -68,7 +68,7 @@
                             {% if rack.site.region %}
                                 <a href="{{ rack.site.region.get_absolute_url }}">{{ rack.site.region }}</a> /
                             {% endif %}
-                            <a href="{% url 'dcim:site' slug=rack.site.slug %}">{{ rack.site }}</a>
+                            <a href="{{ rack.site.get_absolute_url }}">{{ rack.site }}</a>
                         </td>
                     </tr>
                     <tr>

+ 1 - 1
netbox/templates/dcim/site.html

@@ -56,7 +56,7 @@
         </li>
         {% if perms.extras.view_objectchange %}
             <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
-                <a href="{% url 'dcim:site_changelog' slug=object.slug %}">Change Log</a>
+                <a href="{% url 'dcim:site_changelog' pk=object.pk %}">Change Log</a>
             </li>
         {% endif %}
     </ul>

+ 1 - 1
netbox/templates/extras/tag.html

@@ -44,7 +44,7 @@
         </li>
         {% if perms.extras.view_objectchange %}
             <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
-                <a href="{% url 'extras:tag_changelog' slug=object.slug %}">Change Log</a>
+                <a href="{% url 'extras:tag_changelog' pk=object.pk %}">Change Log</a>
             </li>
         {% endif %}
     </ul>

+ 1 - 1
netbox/templates/ipam/prefix.html

@@ -129,7 +129,7 @@
                                 {% if object.site.region %}
                                     <a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> /
                                 {% endif %}
-                                <a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a>
+                                <a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a>
                             {% else %}
                                 <span class="text-muted">None</span>
                             {% endif %}

+ 1 - 1
netbox/templates/ipam/vlan.html

@@ -81,7 +81,7 @@
                                 {% if object.site.region %}
                                     <a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> /
                                 {% endif %}
-                                <a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a>
+                                <a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a>
                             {% else %}
                                 <span class="text-muted">None</span>
                             {% endif %}

+ 1 - 1
netbox/templates/ipam/vlangroup_vlans.html

@@ -8,7 +8,7 @@
         <ol class="breadcrumb">
             <li><a href="{% url 'ipam:vlangroup_list' %}">VLAN Groups</a></li>
             {% if object.site %}
-                <li><a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a></li>
+                <li><a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a></li>
             {% endif %}
             <li>{{ object }}</li>
         </ol>

+ 1 - 1
netbox/templates/tenancy/tenant.html

@@ -51,7 +51,7 @@
         </li>
         {% if perms.extras.view_objectchange %}
             <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
-                <a href="{% url 'tenancy:tenant_changelog' slug=object.slug %}">Change Log</a>
+                <a href="{% url 'tenancy:tenant_changelog' pk=object.pk %}">Change Log</a>
             </li>
         {% endif %}
     </ul>

+ 1 - 1
netbox/tenancy/models.py

@@ -105,7 +105,7 @@ class Tenant(PrimaryModel):
         return self.name
 
     def get_absolute_url(self):
-        return reverse('tenancy:tenant', args=[self.slug])
+        return reverse('tenancy:tenant', args=[self.pk])
 
     def to_csv(self):
         return (

+ 2 - 2
netbox/tenancy/tables.py

@@ -12,7 +12,7 @@ MPTT_LINK = """
 
 COL_TENANT = """
 {% if record.tenant %}
-    <a href="{% url 'tenancy:tenant' slug=record.tenant.slug %}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
+    <a href="{{ record.tenant.get_absolute_url }}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
 {% else %}
     &mdash;
 {% endif %}
@@ -35,7 +35,7 @@ class TenantGroupTable(BaseTable):
         url_params={'group': 'slug'},
         verbose_name='Tenants'
     )
-    actions = ButtonsColumn(TenantGroup, pk_field='slug')
+    actions = ButtonsColumn(TenantGroup)
 
     class Meta(BaseTable.Meta):
         model = TenantGroup

+ 7 - 7
netbox/tenancy/urls.py

@@ -12,9 +12,9 @@ urlpatterns = [
     path('tenant-groups/add/', views.TenantGroupEditView.as_view(), name='tenantgroup_add'),
     path('tenant-groups/import/', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'),
     path('tenant-groups/delete/', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
-    path('tenant-groups/<slug:slug>/edit/', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
-    path('tenant-groups/<slug:slug>/delete/', views.TenantGroupDeleteView.as_view(), name='tenantgroup_delete'),
-    path('tenant-groups/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
+    path('tenant-groups/<int:pk>/edit/', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
+    path('tenant-groups/<int:pk>/delete/', views.TenantGroupDeleteView.as_view(), name='tenantgroup_delete'),
+    path('tenant-groups/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}),
 
     # Tenants
     path('tenants/', views.TenantListView.as_view(), name='tenant_list'),
@@ -22,9 +22,9 @@ urlpatterns = [
     path('tenants/import/', views.TenantBulkImportView.as_view(), name='tenant_import'),
     path('tenants/edit/', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'),
     path('tenants/delete/', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'),
-    path('tenants/<slug:slug>/', views.TenantView.as_view(), name='tenant'),
-    path('tenants/<slug:slug>/edit/', views.TenantEditView.as_view(), name='tenant_edit'),
-    path('tenants/<slug:slug>/delete/', views.TenantDeleteView.as_view(), name='tenant_delete'),
-    path('tenants/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}),
+    path('tenants/<int:pk>/', views.TenantView.as_view(), name='tenant'),
+    path('tenants/<int:pk>/edit/', views.TenantEditView.as_view(), name='tenant_edit'),
+    path('tenants/<int:pk>/delete/', views.TenantDeleteView.as_view(), name='tenant_delete'),
+    path('tenants/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='tenant_changelog', kwargs={'model': Tenant}),
 
 ]

+ 4 - 6
netbox/utilities/tables.py

@@ -147,24 +147,23 @@ class ButtonsColumn(tables.TemplateColumn):
     # Note that braces are escaped to allow for string formatting prior to template rendering
     template_code = """
     {{% if "changelog" in buttons %}}
-        <a href="{{% url '{app_label}:{model_name}_changelog' {pk_field}=record.{pk_field} %}}" class="btn btn-default btn-xs" title="Change log">
+        <a href="{{% url '{app_label}:{model_name}_changelog' pk=record.pk %}}" class="btn btn-default btn-xs" title="Change log">
             <i class="mdi mdi-history"></i>
         </a>
     {{% endif %}}
     {{% if "edit" in buttons and perms.{app_label}.change_{model_name} %}}
-        <a href="{{% url '{app_label}:{model_name}_edit' {pk_field}=record.{pk_field} %}}?return_url={{{{ request.path }}}}{{{{ return_url_extra }}}}" class="btn btn-xs btn-warning" title="Edit">
+        <a href="{{% url '{app_label}:{model_name}_edit' pk=record.pk %}}?return_url={{{{ request.path }}}}{{{{ return_url_extra }}}}" class="btn btn-xs btn-warning" title="Edit">
             <i class="mdi mdi-pencil"></i>
         </a>
     {{% endif %}}
     {{% if "delete" in buttons and perms.{app_label}.delete_{model_name} %}}
-        <a href="{{% url '{app_label}:{model_name}_delete' {pk_field}=record.{pk_field} %}}?return_url={{{{ request.path }}}}{{{{ return_url_extra }}}}" class="btn btn-xs btn-danger" title="Delete">
+        <a href="{{% url '{app_label}:{model_name}_delete' pk=record.pk %}}?return_url={{{{ request.path }}}}{{{{ return_url_extra }}}}" class="btn btn-xs btn-danger" title="Delete">
             <i class="mdi mdi-trash-can-outline"></i>
         </a>
     {{% endif %}}
     """
 
-    def __init__(self, model, *args, pk_field='pk', buttons=None, prepend_template=None, return_url_extra='',
-                 **kwargs):
+    def __init__(self, model, *args, buttons=None, prepend_template=None, return_url_extra='', **kwargs):
         if prepend_template:
             prepend_template = prepend_template.replace('{', '{{')
             prepend_template = prepend_template.replace('}', '}}')
@@ -173,7 +172,6 @@ class ButtonsColumn(tables.TemplateColumn):
         template_code = self.template_code.format(
             app_label=model._meta.app_label,
             model_name=model._meta.model_name,
-            pk_field=pk_field,
             buttons=buttons
         )
 

+ 4 - 18
netbox/utilities/templatetags/buttons.py

@@ -40,16 +40,9 @@ def clone_button(instance):
 
 
 @register.inclusion_tag('buttons/edit.html')
-def edit_button(instance, use_pk=False):
+def edit_button(instance):
     viewname = _get_viewname(instance, 'edit')
-
-    # Assign kwargs
-    if hasattr(instance, 'slug') and not use_pk:
-        kwargs = {'slug': instance.slug}
-    else:
-        kwargs = {'pk': instance.pk}
-
-    url = reverse(viewname, kwargs=kwargs)
+    url = reverse(viewname, kwargs={'pk': instance.pk})
 
     return {
         'url': url,
@@ -57,16 +50,9 @@ def edit_button(instance, use_pk=False):
 
 
 @register.inclusion_tag('buttons/delete.html')
-def delete_button(instance, use_pk=False):
+def delete_button(instance):
     viewname = _get_viewname(instance, 'delete')
-
-    # Assign kwargs
-    if hasattr(instance, 'slug') and not use_pk:
-        kwargs = {'slug': instance.slug}
-    else:
-        kwargs = {'pk': instance.pk}
-
-    url = reverse(viewname, kwargs=kwargs)
+    url = reverse(viewname, kwargs={'pk': instance.pk})
 
     return {
         'url': url,

+ 1 - 9
netbox/utilities/testing/views.py

@@ -5,7 +5,7 @@ from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
 from django.db.models import ManyToManyField
 from django.forms.models import model_to_dict
 from django.test import Client, TestCase as _TestCase, override_settings
-from django.urls import reverse, NoReverseMatch
+from django.urls import reverse
 from django.utils.text import slugify
 from netaddr import IPNetwork
 from taggit.managers import TaggableManager
@@ -205,14 +205,6 @@ class ModelViewTestCase(ModelTestCase):
         if instance is None:
             return reverse(url_format.format(action))
 
-        # Attempt to resolve using slug as the unique identifier if one exists
-        if hasattr(self.model, 'slug'):
-            try:
-                return reverse(url_format.format(action), kwargs={'slug': instance.slug})
-            except NoReverseMatch:
-                pass
-
-        # Default to using the numeric PK to retrieve the URL for an object
         return reverse(url_format.format(action), kwargs={'pk': instance.pk})
 
 

+ 2 - 2
netbox/virtualization/tables.py

@@ -36,7 +36,7 @@ class ClusterTypeTable(BaseTable):
     cluster_count = tables.Column(
         verbose_name='Clusters'
     )
-    actions = ButtonsColumn(ClusterType, pk_field='slug')
+    actions = ButtonsColumn(ClusterType)
 
     class Meta(BaseTable.Meta):
         model = ClusterType
@@ -54,7 +54,7 @@ class ClusterGroupTable(BaseTable):
     cluster_count = tables.Column(
         verbose_name='Clusters'
     )
-    actions = ButtonsColumn(ClusterGroup, pk_field='slug')
+    actions = ButtonsColumn(ClusterGroup)
 
     class Meta(BaseTable.Meta):
         model = ClusterGroup

+ 6 - 6
netbox/virtualization/urls.py

@@ -13,18 +13,18 @@ urlpatterns = [
     path('cluster-types/add/', views.ClusterTypeEditView.as_view(), name='clustertype_add'),
     path('cluster-types/import/', views.ClusterTypeBulkImportView.as_view(), name='clustertype_import'),
     path('cluster-types/delete/', views.ClusterTypeBulkDeleteView.as_view(), name='clustertype_bulk_delete'),
-    path('cluster-types/<slug:slug>/edit/', views.ClusterTypeEditView.as_view(), name='clustertype_edit'),
-    path('cluster-types/<slug:slug>/delete/', views.ClusterTypeDeleteView.as_view(), name='clustertype_delete'),
-    path('cluster-types/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='clustertype_changelog', kwargs={'model': ClusterType}),
+    path('cluster-types/<int:pk>/edit/', views.ClusterTypeEditView.as_view(), name='clustertype_edit'),
+    path('cluster-types/<int:pk>/delete/', views.ClusterTypeDeleteView.as_view(), name='clustertype_delete'),
+    path('cluster-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='clustertype_changelog', kwargs={'model': ClusterType}),
 
     # Cluster groups
     path('cluster-groups/', views.ClusterGroupListView.as_view(), name='clustergroup_list'),
     path('cluster-groups/add/', views.ClusterGroupEditView.as_view(), name='clustergroup_add'),
     path('cluster-groups/import/', views.ClusterGroupBulkImportView.as_view(), name='clustergroup_import'),
     path('cluster-groups/delete/', views.ClusterGroupBulkDeleteView.as_view(), name='clustergroup_bulk_delete'),
-    path('cluster-groups/<slug:slug>/edit/', views.ClusterGroupEditView.as_view(), name='clustergroup_edit'),
-    path('cluster-groups/<slug:slug>/delete/', views.ClusterGroupDeleteView.as_view(), name='clustergroup_delete'),
-    path('cluster-groups/<slug:slug>/changelog/', ObjectChangeLogView.as_view(), name='clustergroup_changelog', kwargs={'model': ClusterGroup}),
+    path('cluster-groups/<int:pk>/edit/', views.ClusterGroupEditView.as_view(), name='clustergroup_edit'),
+    path('cluster-groups/<int:pk>/delete/', views.ClusterGroupDeleteView.as_view(), name='clustergroup_delete'),
+    path('cluster-groups/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='clustergroup_changelog', kwargs={'model': ClusterGroup}),
 
     # Clusters
     path('clusters/', views.ClusterListView.as_view(), name='cluster_list'),