1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #5873: Use numeric IDs in all object URLs

This commit is contained in:
Jeremy Stretch
2021-02-26 17:23:23 -05:00
parent 1dcd857ca6
commit 6a9b50f95d
37 changed files with 97 additions and 126 deletions

View File

@ -11,3 +11,4 @@
### Other Changes ### Other Changes
* [#1638](https://github.com/netbox-community/netbox/issues/1638) - Migrate all primary keys to 64-bit integers * [#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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,7 +74,7 @@
<tr> <tr>
<td>Provider</td> <td>Provider</td>
<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> </td>
</tr> </tr>
<tr> <tr>

View File

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

View File

@ -51,7 +51,7 @@
</li> </li>
{% if perms.extras.view_objectchange %} {% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}> <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> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -23,7 +23,7 @@
{% if object.site.region %} {% if object.site.region %}
<a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> / <a href="{{ object.site.region.get_absolute_url }}">{{ object.site.region }}</a> /
{% endif %} {% endif %}
<a href="{% url 'dcim:site' slug=object.site.slug %}">{{ object.site }}</a> <a href="{{ object.site.get_absolute_url }}">{{ object.site }}</a>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -74,7 +74,7 @@
<tr> <tr>
<td>Device Type</td> <td>Device Type</td>
<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> </td>
</tr> </tr>
<tr> <tr>

View File

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

View File

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

View File

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

View File

@ -56,7 +56,7 @@
</li> </li>
{% if perms.extras.view_objectchange %} {% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}> <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> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

@ -44,7 +44,7 @@
</li> </li>
{% if perms.extras.view_objectchange %} {% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}> <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> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@
</li> </li>
{% if perms.extras.view_objectchange %} {% if perms.extras.view_objectchange %}
<li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}> <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> </li>
{% endif %} {% endif %}
</ul> </ul>

View File

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

View File

@ -12,7 +12,7 @@ MPTT_LINK = """
COL_TENANT = """ COL_TENANT = """
{% if record.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 %} {% else %}
&mdash; &mdash;
{% endif %} {% endif %}
@ -35,7 +35,7 @@ class TenantGroupTable(BaseTable):
url_params={'group': 'slug'}, url_params={'group': 'slug'},
verbose_name='Tenants' verbose_name='Tenants'
) )
actions = ButtonsColumn(TenantGroup, pk_field='slug') actions = ButtonsColumn(TenantGroup)
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = TenantGroup model = TenantGroup

View File

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

View File

@ -147,24 +147,23 @@ class ButtonsColumn(tables.TemplateColumn):
# Note that braces are escaped to allow for string formatting prior to template rendering # Note that braces are escaped to allow for string formatting prior to template rendering
template_code = """ template_code = """
{{% if "changelog" in buttons %}} {{% 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> <i class="mdi mdi-history"></i>
</a> </a>
{{% endif %}} {{% endif %}}
{{% if "edit" in buttons and perms.{app_label}.change_{model_name} %}} {{% 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> <i class="mdi mdi-pencil"></i>
</a> </a>
{{% endif %}} {{% endif %}}
{{% if "delete" in buttons and perms.{app_label}.delete_{model_name} %}} {{% 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> <i class="mdi mdi-trash-can-outline"></i>
</a> </a>
{{% endif %}} {{% endif %}}
""" """
def __init__(self, model, *args, pk_field='pk', buttons=None, prepend_template=None, return_url_extra='', def __init__(self, model, *args, buttons=None, prepend_template=None, return_url_extra='', **kwargs):
**kwargs):
if prepend_template: if prepend_template:
prepend_template = prepend_template.replace('{', '{{') prepend_template = prepend_template.replace('{', '{{')
prepend_template = prepend_template.replace('}', '}}') prepend_template = prepend_template.replace('}', '}}')
@ -173,7 +172,6 @@ class ButtonsColumn(tables.TemplateColumn):
template_code = self.template_code.format( template_code = self.template_code.format(
app_label=model._meta.app_label, app_label=model._meta.app_label,
model_name=model._meta.model_name, model_name=model._meta.model_name,
pk_field=pk_field,
buttons=buttons buttons=buttons
) )

View File

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

View File

@ -5,7 +5,7 @@ from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
from django.db.models import ManyToManyField from django.db.models import ManyToManyField
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.test import Client, TestCase as _TestCase, override_settings 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 django.utils.text import slugify
from netaddr import IPNetwork from netaddr import IPNetwork
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
@ -205,14 +205,6 @@ class ModelViewTestCase(ModelTestCase):
if instance is None: if instance is None:
return reverse(url_format.format(action)) 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}) return reverse(url_format.format(action), kwargs={'pk': instance.pk})

View File

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

View File

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