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'), )