diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index efb1b58d0..f45d75adc 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -25,7 +25,7 @@ from utilities.permissions import get_permission_for_model from utilities.querydict import normalize_querydict, prepare_cloned_fields from utilities.request import safe_for_redirect from utilities.tables import get_table_configs -from utilities.views import GetReturnURLMixin, get_viewname +from utilities.views import GetReturnURLMixin, get_action_url from .base import BaseObjectView from .mixins import ActionsMixin, TableMixin from .utils import get_prerequisite_model @@ -436,8 +436,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): # If this is an HTMX request, return only the rendered deletion form as modal content if htmx_partial(request): - viewname = get_viewname(self.queryset.model, action='delete') - form_url = reverse(viewname, kwargs={'pk': obj.pk}) + form_url = get_action_url(self.queryset.model, action='delete', kwargs={'pk': obj.pk}) return render(request, 'htmx/delete_form.html', { 'object': obj, 'object_type': self.queryset.model._meta.verbose_name, diff --git a/netbox/utilities/forms/fields/dynamic.py b/netbox/utilities/forms/fields/dynamic.py index 085e2f951..83b30ab48 100644 --- a/netbox/utilities/forms/fields/dynamic.py +++ b/netbox/utilities/forms/fields/dynamic.py @@ -2,10 +2,9 @@ import django_filters from django import forms from django.conf import settings from django.forms import BoundField -from django.urls import reverse from utilities.forms import widgets -from utilities.views import get_viewname +from utilities.views import get_action_url __all__ = ( 'DynamicChoiceField', @@ -173,13 +172,12 @@ class DynamicModelChoiceMixin: # Set the data URL on the APISelect widget (if not already set) if not widget.attrs.get('data-url'): - viewname = get_viewname(self.queryset.model, action='list', rest_api=True) - widget.attrs['data-url'] = reverse(viewname) + widget.attrs['data-url'] = get_action_url(self.queryset.model, action='list', rest_api=True) # Include quick add? if self.quick_add: widget.quick_add_context = { - 'url': reverse(get_viewname(self.model, 'add')), + 'url': get_action_url(self.model, action='add'), 'params': {}, } for k, v in self.quick_add_params.items(): diff --git a/netbox/utilities/templatetags/buttons.py b/netbox/utilities/templatetags/buttons.py index 1b43fa395..00ce879a9 100644 --- a/netbox/utilities/templatetags/buttons.py +++ b/netbox/utilities/templatetags/buttons.py @@ -8,7 +8,7 @@ from core.models import ObjectType from extras.models import Bookmark, ExportTemplate, Subscription from netbox.models.features import NotificationsMixin from utilities.querydict import prepare_cloned_fields -from utilities.views import get_viewname +from utilities.views import get_action_url __all__ = ( 'action_buttons', @@ -110,9 +110,8 @@ def subscribe_button(context, instance): @register.inclusion_tag('buttons/clone.html') def clone_button(instance): # Resolve URL path - viewname = get_viewname(instance, 'add') try: - url = reverse(viewname) + url = get_action_url(instance, action='add') except NoReverseMatch: return { 'url': None, @@ -128,8 +127,7 @@ def clone_button(instance): # TODO: Remove in NetBox v4.6 @register.inclusion_tag('buttons/edit.html') def edit_button(instance): - viewname = get_viewname(instance, 'edit') - url = reverse(viewname, kwargs={'pk': instance.pk}) + url = get_action_url(instance, action='edit', kwargs={'pk': instance.pk}) return { 'url': url, @@ -140,8 +138,7 @@ def edit_button(instance): # TODO: Remove in NetBox v4.6 @register.inclusion_tag('buttons/delete.html') def delete_button(instance): - viewname = get_viewname(instance, 'delete') - url = reverse(viewname, kwargs={'pk': instance.pk}) + url = get_action_url(instance, action='delete', kwargs={'pk': instance.pk}) return { 'url': url, @@ -152,8 +149,7 @@ def delete_button(instance): # TODO: Remove in NetBox v4.6 @register.inclusion_tag('buttons/sync.html') def sync_button(instance): - viewname = get_viewname(instance, 'sync') - url = reverse(viewname, kwargs={'pk': instance.pk}) + url = get_action_url(instance, action='sync', kwargs={'pk': instance.pk}) return { 'label': _('Sync'), @@ -169,7 +165,7 @@ def sync_button(instance): @register.inclusion_tag('buttons/add.html') def add_button(model, action='add'): try: - url = reverse(get_viewname(model, action)) + url = get_action_url(model, action=action) except NoReverseMatch: url = None @@ -183,7 +179,7 @@ def add_button(model, action='add'): @register.inclusion_tag('buttons/import.html') def import_button(model, action='bulk_import'): try: - url = reverse(get_viewname(model, action)) + url = get_action_url(model, action=action) except NoReverseMatch: url = None @@ -219,7 +215,7 @@ def export_button(context, model): @register.inclusion_tag('buttons/bulk_edit.html', takes_context=True) def bulk_edit_button(context, model, action='bulk_edit', query_params=None): try: - url = reverse(get_viewname(model, action)) + url = get_action_url(model, action=action) if query_params: url = f'{url}?{query_params.urlencode()}' except NoReverseMatch: @@ -236,7 +232,7 @@ def bulk_edit_button(context, model, action='bulk_edit', query_params=None): @register.inclusion_tag('buttons/bulk_delete.html', takes_context=True) def bulk_delete_button(context, model, action='bulk_delete', query_params=None): try: - url = reverse(get_viewname(model, action)) + url = get_action_url(model, action=action) if query_params: url = f'{url}?{query_params.urlencode()}' except NoReverseMatch: diff --git a/netbox/utilities/templatetags/tabs.py b/netbox/utilities/templatetags/tabs.py index 83eacd663..10153333b 100644 --- a/netbox/utilities/templatetags/tabs.py +++ b/netbox/utilities/templatetags/tabs.py @@ -1,10 +1,9 @@ from django import template -from django.urls import reverse from django.urls.exceptions import NoReverseMatch from django.utils.module_loading import import_string from netbox.registry import registry -from utilities.views import get_viewname +from utilities.views import get_action_url __all__ = ( 'model_view_tabs', @@ -39,10 +38,9 @@ def model_view_tabs(context, instance): continue if attrs := tab.render(instance): - viewname = get_viewname(instance, action=config['name']) active_tab = context.get('tab') try: - url = reverse(viewname, args=[instance.pk]) + url = get_action_url(instance, action=config['name'], kwargs={'pk': instance.pk}) except NoReverseMatch: # No URL has been registered for this view; skip continue