#20048 add get_action_url utility function

This commit is contained in:
Arthur 2025-08-07 13:48:19 -07:00
parent fa262adc6f
commit d7e92bdfb7
4 changed files with 16 additions and 25 deletions

View File

@ -25,7 +25,7 @@ from utilities.permissions import get_permission_for_model
from utilities.querydict import normalize_querydict, prepare_cloned_fields from utilities.querydict import normalize_querydict, prepare_cloned_fields
from utilities.request import safe_for_redirect from utilities.request import safe_for_redirect
from utilities.tables import get_table_configs 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 .base import BaseObjectView
from .mixins import ActionsMixin, TableMixin from .mixins import ActionsMixin, TableMixin
from .utils import get_prerequisite_model 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 this is an HTMX request, return only the rendered deletion form as modal content
if htmx_partial(request): if htmx_partial(request):
viewname = get_viewname(self.queryset.model, action='delete') form_url = get_action_url(self.queryset.model, action='delete', kwargs={'pk': obj.pk})
form_url = reverse(viewname, kwargs={'pk': obj.pk})
return render(request, 'htmx/delete_form.html', { return render(request, 'htmx/delete_form.html', {
'object': obj, 'object': obj,
'object_type': self.queryset.model._meta.verbose_name, 'object_type': self.queryset.model._meta.verbose_name,

View File

@ -2,10 +2,9 @@ import django_filters
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.forms import BoundField from django.forms import BoundField
from django.urls import reverse
from utilities.forms import widgets from utilities.forms import widgets
from utilities.views import get_viewname from utilities.views import get_action_url
__all__ = ( __all__ = (
'DynamicChoiceField', 'DynamicChoiceField',
@ -173,13 +172,12 @@ class DynamicModelChoiceMixin:
# Set the data URL on the APISelect widget (if not already set) # Set the data URL on the APISelect widget (if not already set)
if not widget.attrs.get('data-url'): if not widget.attrs.get('data-url'):
viewname = get_viewname(self.queryset.model, action='list', rest_api=True) widget.attrs['data-url'] = get_action_url(self.queryset.model, action='list', rest_api=True)
widget.attrs['data-url'] = reverse(viewname)
# Include quick add? # Include quick add?
if self.quick_add: if self.quick_add:
widget.quick_add_context = { widget.quick_add_context = {
'url': reverse(get_viewname(self.model, 'add')), 'url': get_action_url(self.model, action='add'),
'params': {}, 'params': {},
} }
for k, v in self.quick_add_params.items(): for k, v in self.quick_add_params.items():

View File

@ -8,7 +8,7 @@ from core.models import ObjectType
from extras.models import Bookmark, ExportTemplate, Subscription from extras.models import Bookmark, ExportTemplate, Subscription
from netbox.models.features import NotificationsMixin from netbox.models.features import NotificationsMixin
from utilities.querydict import prepare_cloned_fields from utilities.querydict import prepare_cloned_fields
from utilities.views import get_viewname from utilities.views import get_action_url
__all__ = ( __all__ = (
'action_buttons', 'action_buttons',
@ -110,9 +110,8 @@ def subscribe_button(context, instance):
@register.inclusion_tag('buttons/clone.html') @register.inclusion_tag('buttons/clone.html')
def clone_button(instance): def clone_button(instance):
# Resolve URL path # Resolve URL path
viewname = get_viewname(instance, 'add')
try: try:
url = reverse(viewname) url = get_action_url(instance, action='add')
except NoReverseMatch: except NoReverseMatch:
return { return {
'url': None, 'url': None,
@ -128,8 +127,7 @@ def clone_button(instance):
# TODO: Remove in NetBox v4.6 # TODO: Remove in NetBox v4.6
@register.inclusion_tag('buttons/edit.html') @register.inclusion_tag('buttons/edit.html')
def edit_button(instance): def edit_button(instance):
viewname = get_viewname(instance, 'edit') url = get_action_url(instance, action='edit', kwargs={'pk': instance.pk})
url = reverse(viewname, kwargs={'pk': instance.pk})
return { return {
'url': url, 'url': url,
@ -140,8 +138,7 @@ def edit_button(instance):
# TODO: Remove in NetBox v4.6 # TODO: Remove in NetBox v4.6
@register.inclusion_tag('buttons/delete.html') @register.inclusion_tag('buttons/delete.html')
def delete_button(instance): def delete_button(instance):
viewname = get_viewname(instance, 'delete') url = get_action_url(instance, action='delete', kwargs={'pk': instance.pk})
url = reverse(viewname, kwargs={'pk': instance.pk})
return { return {
'url': url, 'url': url,
@ -152,8 +149,7 @@ def delete_button(instance):
# TODO: Remove in NetBox v4.6 # TODO: Remove in NetBox v4.6
@register.inclusion_tag('buttons/sync.html') @register.inclusion_tag('buttons/sync.html')
def sync_button(instance): def sync_button(instance):
viewname = get_viewname(instance, 'sync') url = get_action_url(instance, action='sync', kwargs={'pk': instance.pk})
url = reverse(viewname, kwargs={'pk': instance.pk})
return { return {
'label': _('Sync'), 'label': _('Sync'),
@ -169,7 +165,7 @@ def sync_button(instance):
@register.inclusion_tag('buttons/add.html') @register.inclusion_tag('buttons/add.html')
def add_button(model, action='add'): def add_button(model, action='add'):
try: try:
url = reverse(get_viewname(model, action)) url = get_action_url(model, action=action)
except NoReverseMatch: except NoReverseMatch:
url = None url = None
@ -183,7 +179,7 @@ def add_button(model, action='add'):
@register.inclusion_tag('buttons/import.html') @register.inclusion_tag('buttons/import.html')
def import_button(model, action='bulk_import'): def import_button(model, action='bulk_import'):
try: try:
url = reverse(get_viewname(model, action)) url = get_action_url(model, action=action)
except NoReverseMatch: except NoReverseMatch:
url = None url = None
@ -219,7 +215,7 @@ def export_button(context, model):
@register.inclusion_tag('buttons/bulk_edit.html', takes_context=True) @register.inclusion_tag('buttons/bulk_edit.html', takes_context=True)
def bulk_edit_button(context, model, action='bulk_edit', query_params=None): def bulk_edit_button(context, model, action='bulk_edit', query_params=None):
try: try:
url = reverse(get_viewname(model, action)) url = get_action_url(model, action=action)
if query_params: if query_params:
url = f'{url}?{query_params.urlencode()}' url = f'{url}?{query_params.urlencode()}'
except NoReverseMatch: 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) @register.inclusion_tag('buttons/bulk_delete.html', takes_context=True)
def bulk_delete_button(context, model, action='bulk_delete', query_params=None): def bulk_delete_button(context, model, action='bulk_delete', query_params=None):
try: try:
url = reverse(get_viewname(model, action)) url = get_action_url(model, action=action)
if query_params: if query_params:
url = f'{url}?{query_params.urlencode()}' url = f'{url}?{query_params.urlencode()}'
except NoReverseMatch: except NoReverseMatch:

View File

@ -1,10 +1,9 @@
from django import template from django import template
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch from django.urls.exceptions import NoReverseMatch
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
from netbox.registry import registry from netbox.registry import registry
from utilities.views import get_viewname from utilities.views import get_action_url
__all__ = ( __all__ = (
'model_view_tabs', 'model_view_tabs',
@ -39,10 +38,9 @@ def model_view_tabs(context, instance):
continue continue
if attrs := tab.render(instance): if attrs := tab.render(instance):
viewname = get_viewname(instance, action=config['name'])
active_tab = context.get('tab') active_tab = context.get('tab')
try: try:
url = reverse(viewname, args=[instance.pk]) url = get_action_url(instance, action=config['name'], kwargs={'pk': instance.pk})
except NoReverseMatch: except NoReverseMatch:
# No URL has been registered for this view; skip # No URL has been registered for this view; skip
continue continue