- {% trans "Site" %} |
+ {% trans "Region" %} |
- {% if object.site.region %}
- {{ object.site.region|linkify }} /
- {% endif %}
- {{ object.site|linkify }}
+ {% nested_tree object.site.region %}
|
+
+ {% trans "Site" %} |
+ {{ object.site|linkify }} |
+
{% 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 8edb75f32..3d145145f 100644
--- a/netbox/templates/dcim/rackreservation.html
+++ b/netbox/templates/dcim/rackreservation.html
@@ -4,6 +4,7 @@
{% load static %}
{% load plugins %}
{% load i18n %}
+{% load mptt %}
{% block breadcrumbs %}
{{ block.super }}
@@ -20,25 +21,24 @@
- {% with rack=object.rack %}
-
- {% trans "Site" %} |
-
- {% if rack.site.region %}
- {{ rack.site.region|linkify }} /
- {% endif %}
- {{ 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 7f43a0ab3..16a870182 100644
--- a/netbox/templates/dcim/site.html
+++ b/netbox/templates/dcim/site.html
@@ -3,6 +3,7 @@
{% load plugins %}
{% load tz %}
{% load i18n %}
+{% load mptt %}
{% block breadcrumbs %}
{{ block.super }}
@@ -29,27 +30,13 @@
{% trans "Region" %} |
- {% if object.region %}
- {% for region in object.region.get_ancestors %}
- {{ region|linkify }} /
- {% endfor %}
- {{ object.region|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
+ {% 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 71b240ced..ec6138d69 100644
--- a/netbox/templates/ipam/prefix.html
+++ b/netbox/templates/ipam/prefix.html
@@ -3,6 +3,7 @@
{% load helpers %}
{% load plugins %}
{% load i18n %}
+{% load mptt %}
{% block content %}
@@ -44,18 +45,17 @@
{% endif %}
+ {% if object.site.region %}
+
+ {% trans "Region" %} |
+
+ {% nested_tree object.site.region %}
+ |
+
+ {% endif %}
{% trans "Site" %} |
-
- {% if object.site %}
- {% if object.site.region %}
- {{ object.site.region|linkify }} /
- {% endif %}
- {{ object.site|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
+ {{ object.site|linkify|placeholder }} |
{% trans "VLAN" %} |
diff --git a/netbox/templates/ipam/vlan.html b/netbox/templates/ipam/vlan.html
index 4ca045d4b..a5ed9d643 100644
--- a/netbox/templates/ipam/vlan.html
+++ b/netbox/templates/ipam/vlan.html
@@ -3,6 +3,7 @@
{% load render_table from django_tables2 %}
{% load plugins %}
{% load i18n %}
+{% load mptt %}
{% block content %}
@@ -13,18 +14,17 @@
+ {% if object.site.region %}
+
+ {% trans "Region" %} |
+
+ {% nested_tree object.site.region %}
+ |
+
+ {% endif %}
{% trans "Site" %} |
-
- {% if object.site %}
- {% if object.site.region %}
- {{ object.site.region|linkify }} /
- {% endif %}
- {{ object.site|linkify }}
- {% else %}
- {{ ''|placeholder }}
- {% endif %}
- |
+ {{ object.site|linkify|placeholder }} |
{% trans "Group" %} |
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
+ )
+ )