diff --git a/netbox/dcim/models/sites.py b/netbox/dcim/models/sites.py
index 3bd434648..43c47a359 100644
--- a/netbox/dcim/models/sites.py
+++ b/netbox/dcim/models/sites.py
@@ -69,7 +69,7 @@ class Region(NestedGroupModel):
def get_site_count(self):
return Site.objects.filter(
Q(region=self) |
- Q(region__in=self.get_descendants())
+ Q(region__in=self.descendants())
).count()
@@ -124,7 +124,7 @@ class SiteGroup(NestedGroupModel):
def get_site_count(self):
return Site.objects.filter(
Q(group=self) |
- Q(group__in=self.get_descendants())
+ Q(group__in=self.descendants())
).count()
diff --git a/netbox/dcim/signals.py b/netbox/dcim/signals.py
index 7ef08d2cc..b27fcf29a 100644
--- a/netbox/dcim/signals.py
+++ b/netbox/dcim/signals.py
@@ -22,8 +22,8 @@ def handle_location_site_change(instance, created, **kwargs):
object instead of calling update() on the QuerySet to ensure the proper change records get created for each.
"""
if not created:
- instance.get_descendants().update(site=instance.site)
- locations = instance.get_descendants(include_self=True).values_list('pk', flat=True)
+ instance.descendants().update(site=instance.site)
+ locations = instance.descendants(include_self=True).values_list('pk', flat=True)
Rack.objects.filter(location__in=locations).update(site=instance.site)
Device.objects.filter(location__in=locations).update(site=instance.site)
PowerPanel.objects.filter(location__in=locations).update(site=instance.site)
diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py
index 67fcc528c..bc6fed495 100644
--- a/netbox/dcim/views.py
+++ b/netbox/dcim/views.py
@@ -198,7 +198,7 @@ class PathTraceView(generic.ObjectView):
#
class RegionListView(generic.ObjectListView):
- queryset = Region.objects.all()
+ queryset = Region.objects.all().order_siblings_by("name")
# queryset = Region.objects.add_related_count(
# Region.objects.all(),
# Site,
@@ -216,7 +216,7 @@ class RegionView(generic.ObjectView):
queryset = Region.objects.all()
def get_extra_context(self, request, instance):
- regions = instance.get_descendants(include_self=True)
+ regions = instance.descendants(include_self=True)
related_models = (
(Site.objects.restrict(request.user, 'view').filter(region__in=regions), 'region_id'),
(Location.objects.restrict(request.user, 'view').filter(site__region__in=regions), 'region_id'),
@@ -299,7 +299,7 @@ class SiteGroupView(generic.ObjectView):
queryset = SiteGroup.objects.all()
def get_extra_context(self, request, instance):
- groups = instance.get_descendants(include_self=True)
+ groups = instance.descendants(include_self=True)
related_models = (
(Site.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
(Location.objects.restrict(request.user, 'view').filter(site__group__in=groups), 'site_group_id'),
@@ -487,7 +487,7 @@ class LocationView(generic.ObjectView):
queryset = Location.objects.all()
def get_extra_context(self, request, instance):
- locations = instance.get_descendants(include_self=True)
+ locations = instance.descendants(include_self=True)
related_models = (
(Rack.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'),
(Device.objects.restrict(request.user, 'view').filter(location__in=locations), 'location_id'),
diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py
index 0281bf847..76138ed16 100644
--- a/netbox/extras/querysets.py
+++ b/netbox/extras/querysets.py
@@ -33,11 +33,11 @@ class ConfigContextQuerySet(RestrictedQuerySet):
# Match against the directly assigned region as well as any parent regions.
region = getattr(obj.site, 'region', None)
- regions = region.get_ancestors(include_self=True) if region else []
+ regions = region.ancestors(include_self=True) if region else []
# Match against the directly assigned site group as well as any parent site groups.
sitegroup = getattr(obj.site, 'group', None)
- sitegroups = sitegroup.get_ancestors(include_self=True) if sitegroup else []
+ sitegroups = sitegroup.ancestors(include_self=True) if sitegroup else []
queryset = self.filter(
Q(regions__in=regions) | Q(regions=None),
diff --git a/netbox/ipam/querysets.py b/netbox/ipam/querysets.py
index 9f4463f61..d2ab6e37d 100644
--- a/netbox/ipam/querysets.py
+++ b/netbox/ipam/querysets.py
@@ -43,12 +43,12 @@ class VLANQuerySet(RestrictedQuerySet):
if device.site.region:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'),
- scope_id__in=device.site.region.get_ancestors(include_self=True)
+ scope_id__in=device.site.region.ancestors(include_self=True)
)
if device.site.group:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'),
- scope_id__in=device.site.group.get_ancestors(include_self=True)
+ scope_id__in=device.site.group.ancestors(include_self=True)
)
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'site'),
@@ -57,7 +57,7 @@ class VLANQuerySet(RestrictedQuerySet):
if device.location:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'location'),
- scope_id__in=device.location.get_ancestors(include_self=True)
+ scope_id__in=device.location.ancestors(include_self=True)
)
if device.rack:
q |= Q(
@@ -102,12 +102,12 @@ class VLANQuerySet(RestrictedQuerySet):
if site.region:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'region'),
- scope_id__in=site.region.get_ancestors(include_self=True)
+ scope_id__in=site.region.ancestors(include_self=True)
)
if site.group:
q |= Q(
scope_type=ContentType.objects.get_by_natural_key('dcim', 'sitegroup'),
- scope_id__in=site.group.get_ancestors(include_self=True)
+ scope_id__in=site.group.ancestors(include_self=True)
)
vlan_groups = VLANGroup.objects.filter(q)
diff --git a/netbox/netbox/models/__init__.py b/netbox/netbox/models/__init__.py
index fc59f15a5..969764b39 100644
--- a/netbox/netbox/models/__init__.py
+++ b/netbox/netbox/models/__init__.py
@@ -106,7 +106,7 @@ class PrimaryModel(NetBoxModel):
class NestedGroupModel(CloningMixin, NetBoxFeatureSet, TreeNode):
"""
Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest
- recursively using MPTT. Within each parent, each child instance must have a unique name.
+ recursively using tree-queries. Within each parent, each child instance must have a unique name.
"""
name = models.CharField(
max_length=100
@@ -128,15 +128,6 @@ class NestedGroupModel(CloningMixin, NetBoxFeatureSet, TreeNode):
def __str__(self):
return self.name
- def clean(self):
- super().clean()
-
- # An MPTT model cannot be its own parent
- if self.pk and self.parent and self.parent in self.get_descendants(include_self=True):
- raise ValidationError({
- "parent": f"Cannot assign self or child {self._meta.verbose_name} as parent."
- })
-
class OrganizationalModel(NetBoxFeatureSet, models.Model):
"""
diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py
index 66ee787a8..83856a046 100644
--- a/netbox/netbox/tables/columns.py
+++ b/netbox/netbox/tables/columns.py
@@ -538,7 +538,7 @@ class MPTTColumn(tables.TemplateColumn):
template_code = """
{% load helpers %}
{% if not table.order_by %}
- {% for i in record.level|as_range %}{% endfor %}
+ {% for i in record.tree_depth|as_range %}{% endfor %}
{% endif %}
{{ record.name }}
"""
diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py
index 8760dfa71..1af0dfb8c 100644
--- a/netbox/tenancy/views.py
+++ b/netbox/tenancy/views.py
@@ -60,7 +60,7 @@ class TenantGroupView(generic.ObjectView):
queryset = TenantGroup.objects.all()
def get_extra_context(self, request, instance):
- groups = instance.get_descendants(include_self=True)
+ groups = instance.descendants(include_self=True)
related_models = (
(Tenant.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
)
@@ -219,7 +219,7 @@ class ContactGroupView(generic.ObjectView):
queryset = ContactGroup.objects.all()
def get_extra_context(self, request, instance):
- groups = instance.get_descendants(include_self=True)
+ groups = instance.descendants(include_self=True)
related_models = (
(Contact.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
)
diff --git a/netbox/utilities/filters.py b/netbox/utilities/filters.py
index 1bf17beae..24aa6279b 100644
--- a/netbox/utilities/filters.py
+++ b/netbox/utilities/filters.py
@@ -116,7 +116,7 @@ class TreeNodeMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilter):
return super().get_filter_predicate(v)
def filter(self, qs, value):
- value = [node.get_descendants(include_self=True) if not isinstance(node, str) else node for node in value]
+ value = [node.descendants(include_self=True) if not isinstance(node, str) else node for node in value]
return super().filter(qs, value)
diff --git a/netbox/wireless/views.py b/netbox/wireless/views.py
index 049a68bba..121aa6db9 100644
--- a/netbox/wireless/views.py
+++ b/netbox/wireless/views.py
@@ -29,7 +29,7 @@ class WirelessLANGroupView(generic.ObjectView):
queryset = WirelessLANGroup.objects.all()
def get_extra_context(self, request, instance):
- groups = instance.get_descendants(include_self=True)
+ groups = instance.descendants(include_self=True)
related_models = (
(WirelessLAN.objects.restrict(request.user, 'view').filter(group__in=groups), 'group_id'),
)