diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index 24c22ec0c..397a5a4ef 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -10,7 +10,7 @@ from django.utils.safestring import mark_safe from django_tables2.utils import Accessor from extras.choices import CustomFieldTypeChoices -from utilities.utils import content_type_identifier, content_type_name +from utilities.utils import content_type_identifier, content_type_name, resolve_namespace __all__ = ( 'ActionsColumn', @@ -134,7 +134,7 @@ class ActionsColumn(tables.Column): return '' model = table.Meta.model - viewname_base = f'{model._meta.app_label}:{model._meta.model_name}' + viewname_base = f'{resolve_namespace(model)}:{model._meta.model_name}' request = getattr(table, 'context', {}).get('request') url_appendix = f'?return_url={request.path}' if request else '' diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 0e45cb581..be7dc97d1 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -16,9 +16,10 @@ from django.utils.safestring import mark_safe from markdown import markdown from netbox.config import get_config +from netbox.settings import PLUGINS from utilities.forms import get_selected_values, TableConfigForm from utilities.markdown import StrikethroughExtension -from utilities.utils import foreground_color +from utilities.utils import foreground_color, resolve_namespace register = template.Library() @@ -115,7 +116,8 @@ def viewname(model, action): """ Return the view name for the given model and action. Does not perform any validation. """ - return f'{model._meta.app_label}:{model._meta.model_name}_{action}' + namespace = resolve_namespace(model) + return f'{namespace}:{model._meta.model_name}_{action}' @register.filter() @@ -123,7 +125,8 @@ def validated_viewname(model, action): """ Return the view name for the given model and action if valid, or None if invalid. """ - viewname = f'{model._meta.app_label}:{model._meta.model_name}_{action}' + namespace = resolve_namespace(model) + viewname = f'{namespace}:{model._meta.model_name}_{action}' try: # Validate and return the view name. We don't return the actual URL yet because many of the templates # are written to pass a name to {% url %}. diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index 444b87523..bf2b1638c 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -13,10 +13,20 @@ from jinja2.sandbox import SandboxedEnvironment from mptt.models import MPTTModel from dcim.choices import CableLengthUnitChoices +from extras.plugins import PluginConfig from extras.utils import is_taggable from utilities.constants import HTTP_REQUEST_META_SAFE_COPY +def resolve_namespace(instance): + """ + Get the appropriate namepsace for the app based on whether it is a Plugin or base application + """ + if isinstance(instance._meta.app_config, PluginConfig): + return f'plugins:{instance._meta.app_label}' + return f'{instance._meta.app_label}' + + def csv_format(data): """ Encapsulate any data which contains a comma within double quotes.