diff --git a/netbox/dcim/templatetags/__init__.py b/netbox/dcim/templatetags/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/netbox/dcim/templatetags/mptt.py b/netbox/dcim/templatetags/mptt.py
deleted file mode 100644
index 9b76e525c..000000000
--- a/netbox/dcim/templatetags/mptt.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from django import template
-from django.utils.safestring import mark_safe
-from dcim.models import Site
-
-register = template.Library()
-
-
-@register.simple_tag(takes_context=True)
-def nested_tree(context, obj):
- """
- Renders hierarchical region data for a given object.
- """
- # Retrieve the region or site information
- if isinstance(obj, Site):
- region = obj.region
- else:
- region = getattr(obj, 'region', None) or getattr(obj.site, 'region', None)
-
- # Return a placeholder if no region or site is found
- if not region:
- return mark_safe('—')
-
- # Build the region links if the region is available
- return mark_safe(
- ' / '.join(
- '{}'.format(context['request'].build_absolute_uri(reg.get_absolute_url()), reg)
- for reg in region.get_ancestors(include_self=True)
- ) if region else ''
- )
diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html
index 3367f17eb..39e78c81b 100644
--- a/netbox/templates/dcim/device.html
+++ b/netbox/templates/dcim/device.html
@@ -16,9 +16,7 @@
{% trans "Region" %} |
-
- {% nested_tree object %}
- |
+ {% nested_tree object.site.region %} |
{% trans "Site" %} |
@@ -26,16 +24,7 @@
{% trans "Location" %} |
-
- {% if object.location %}
- {% for location in object.location.get_ancestors %}
- {{ location|linkify }} /
- {% endfor %}
- {{ object.location|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
+ {% nested_tree object.location %} |
{% trans "Rack" %} |
diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html
index fa48470e3..857061d00 100644
--- a/netbox/templates/dcim/rack.html
+++ b/netbox/templates/dcim/rack.html
@@ -18,7 +18,7 @@
{% trans "Region" %} |
- {% nested_tree object %}
+ {% nested_tree object.site.region %}
|
@@ -27,16 +27,7 @@
{% trans "Location" %} |
-
- {% if object.location %}
- {% for location in object.location.get_ancestors %}
- {{ location|linkify }} /
- {% endfor %}
- {{ object.location|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
+ {% nested_tree object.location %} |
{% trans "Facility ID" %} |
diff --git a/netbox/templates/dcim/rackreservation.html b/netbox/templates/dcim/rackreservation.html
index 08eb1e912..3d145145f 100644
--- a/netbox/templates/dcim/rackreservation.html
+++ b/netbox/templates/dcim/rackreservation.html
@@ -21,26 +21,24 @@
- {% with rack=object.rack %}
-
- {% trans "Region" %} |
-
- {% nested_tree rack %}
- |
-
-
- {% trans "Site" %} |
- {{ rack.site|linkify }} |
-
-
- {% trans "Location" %} |
- {{ rack.location|linkify|placeholder }} |
-
-
- {% trans "Rack" %} |
- {{ rack|linkify }} |
-
- {% endwith %}
+
+ {% trans "Region" %} |
+
+ {% nested_tree object.rack.site.region %}
+ |
+
+
+ {% trans "Site" %} |
+ {{ object.rack.site|linkify }} |
+
+
+ {% trans "Location" %} |
+ {{ object.rack.location|linkify|placeholder }} |
+
+
+ {% trans "Rack" %} |
+ {{ object.rack|linkify }} |
+
diff --git a/netbox/templates/dcim/site.html b/netbox/templates/dcim/site.html
index 56a675ea9..16a870182 100644
--- a/netbox/templates/dcim/site.html
+++ b/netbox/templates/dcim/site.html
@@ -30,20 +30,13 @@
{% trans "Region" %} |
- {% nested_tree object %}
+ {% nested_tree object.region %}
|
{% trans "Group" %} |
- {% if object.group %}
- {% for group in object.group.get_ancestors %}
- {{ group|linkify }} /
- {% endfor %}
- {{ object.group|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
+ {% nested_tree object.group %}
|
diff --git a/netbox/templates/ipam/prefix.html b/netbox/templates/ipam/prefix.html
index c71707da7..ec6138d69 100644
--- a/netbox/templates/ipam/prefix.html
+++ b/netbox/templates/ipam/prefix.html
@@ -45,15 +45,17 @@
{% endif %}
+ {% if object.site.region %}
+
+ {% trans "Region" %} |
+
+ {% nested_tree object.site.region %}
+ |
+
+ {% endif %}
- {% trans "Region" %} |
-
- {% nested_tree object %}
- |
-
-
- {% trans "Site" %} |
- {{ object.site|linkify|placeholder }} |
+ {% trans "Site" %} |
+ {{ object.site|linkify|placeholder }} |
{% trans "VLAN" %} |
diff --git a/netbox/templates/ipam/vlan.html b/netbox/templates/ipam/vlan.html
index 3f9cc2d25..a5ed9d643 100644
--- a/netbox/templates/ipam/vlan.html
+++ b/netbox/templates/ipam/vlan.html
@@ -14,12 +14,14 @@
-
- {% trans "Region" %} |
-
- {% nested_tree object %}
- |
-
+ {% if object.site.region %}
+
+ {% trans "Region" %} |
+
+ {% nested_tree object.site.region %}
+ |
+
+ {% endif %}
{% trans "Site" %} |
{{ object.site|linkify|placeholder }} |
diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py
index aaee9679c..941534b75 100644
--- a/netbox/utilities/templatetags/helpers.py
+++ b/netbox/utilities/templatetags/helpers.py
@@ -27,6 +27,7 @@ __all__ = (
'icon_from_status',
'kg_to_pounds',
'meters_to_feet',
+ 'nested_tree',
'percentage',
'querystring',
'startswith',
diff --git a/netbox/utilities/templatetags/mptt.py b/netbox/utilities/templatetags/mptt.py
new file mode 100644
index 000000000..783c2654f
--- /dev/null
+++ b/netbox/utilities/templatetags/mptt.py
@@ -0,0 +1,20 @@
+from django import template
+from django.utils.safestring import mark_safe
+
+register = template.Library()
+
+
+@register.simple_tag()
+def nested_tree(obj):
+ """
+ Renders the entire hierarchy of a recursively-nested object (such as Region or SiteGroup).
+ """
+ if not obj:
+ return mark_safe('—')
+
+ nodes = obj.get_ancestors(include_self=True)
+ return mark_safe(
+ ' / '.join(
+ f'{node}' for node in nodes
+ )
+ )