diff --git a/netbox/utilities/tables.py b/netbox/utilities/tables.py
index 9000af110..82f25ebaf 100644
--- a/netbox/utilities/tables.py
+++ b/netbox/utilities/tables.py
@@ -216,18 +216,19 @@ class ButtonsColumn(tables.TemplateColumn):
attrs = {'td': {'class': 'text-end text-nowrap noprint'}}
# Note that braces are escaped to allow for string formatting prior to template rendering
template_code = """
+ {{% load helpers %}}
{{% if "changelog" in buttons %}}
-
+
{{% endif %}}
{{% if "edit" in buttons and perms.{app_label}.change_{model_name} %}}
-
+
{{% endif %}}
{{% if "delete" in buttons and perms.{app_label}.delete_{model_name} %}}
-
+
{{% endif %}}
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.