diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index f819c86b6..7af5cf109 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -155,6 +155,7 @@ Where it is desired to limit the range of available VLANs within a group, users * [#8682](https://github.com/netbox-community/netbox/issues/8682) - Limit available VLANs by group min/max VIDs * [#8683](https://github.com/netbox-community/netbox/issues/8683) - Fix `ZoneInfoNotFoundError` exception under Python 3.9+ * [#8761](https://github.com/netbox-community/netbox/issues/8761) - Correct view name resolution under journal entry views +* [#8764](https://github.com/netbox-community/netbox/issues/8764) - Correct view name resolution for dynamic form fields ### Other Changes diff --git a/netbox/utilities/forms/fields/dynamic.py b/netbox/utilities/forms/fields/dynamic.py index 1bc8b9ec4..f83fc6a7c 100644 --- a/netbox/utilities/forms/fields/dynamic.py +++ b/netbox/utilities/forms/fields/dynamic.py @@ -5,6 +5,7 @@ from django.forms import BoundField from django.urls import reverse from utilities.forms import widgets +from utilities.utils import get_viewname __all__ = ( 'DynamicModelChoiceField', @@ -101,10 +102,8 @@ class DynamicModelChoiceMixin: # Set the data URL on the APISelect widget (if not already set) widget = bound_field.field.widget if not widget.attrs.get('data-url'): - app_label = self.queryset.model._meta.app_label - model_name = self.queryset.model._meta.model_name - data_url = reverse('{}-api:{}-list'.format(app_label, model_name)) - widget.attrs['data-url'] = data_url + viewname = get_viewname(self.queryset.model, action='list', rest_api=True) + widget.attrs['data-url'] = reverse(viewname) return bound_field diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 4a46b7d15..3ef33c0f7 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -17,22 +17,35 @@ from extras.utils import is_taggable from utilities.constants import HTTP_REQUEST_META_SAFE_COPY -def get_viewname(model, action=None): +def get_viewname(model, action=None, rest_api=False): """ Return the view name for the given model and action, if valid. :param model: The model or instance to which the view applies :param action: A string indicating the desired action (if any); e.g. "add" or "list" + :param rest_api: A boolean indicating whether this is a REST API view """ - viewname = f'{model._meta.app_label}:{model._meta.model_name}' + is_plugin = isinstance(model._meta.app_config, PluginConfig) + app_label = model._meta.app_label + model_name = model._meta.model_name - # Determine whether this is a plugin view and adjust the namespace appropriately - if isinstance(model._meta.app_config, PluginConfig): - viewname = f'plugins:{viewname}' + if rest_api: + if is_plugin: + viewname = f'plugins-api:{app_label}:{model_name}' + else: + viewname = f'{app_label}-api:{model_name}' + # Append the action, if any + if action: + viewname = f'{viewname}-{action}' - # Append the action, if any - if action: - viewname = f'{viewname}_{action}' + else: + viewname = f'{app_label}:{model_name}' + # Prepend the plugins namespace if this is a plugin model + if is_plugin: + viewname = f'plugins:{viewname}' + # Append the action, if any + if action: + viewname = f'{viewname}_{action}' return viewname