mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Replace annotate_depth() with annotate_tree()
This commit is contained in:
parent
bdb8263610
commit
0d68d0c059
@ -3,34 +3,20 @@ from utilities.querysets import RestrictedQuerySet
|
||||
|
||||
class PrefixQuerySet(RestrictedQuerySet):
|
||||
|
||||
def annotate_depth(self, limit=None):
|
||||
def annotate_tree(self):
|
||||
"""
|
||||
Iterate through a QuerySet of Prefixes and annotate the hierarchical level of each. While it would be preferable
|
||||
to do this using .annotate() on the QuerySet to count the unique parents of each prefix, that approach introduces
|
||||
performance issues at scale.
|
||||
|
||||
Because we're adding a non-field attribute to the model, annotation must be made *after* any QuerySet
|
||||
modifications.
|
||||
Annotate the number of parent and child prefixes for each Prefix. Raw SQL is needed for these subqueries
|
||||
because we need to cast NULL VRF values to integers for comparison. (NULL != NULL).
|
||||
"""
|
||||
queryset = self
|
||||
stack = []
|
||||
for p in queryset:
|
||||
try:
|
||||
prev_p = stack[-1]
|
||||
except IndexError:
|
||||
prev_p = None
|
||||
if prev_p is not None:
|
||||
while (p.prefix not in prev_p.prefix) or p.prefix == prev_p.prefix:
|
||||
stack.pop()
|
||||
try:
|
||||
prev_p = stack[-1]
|
||||
except IndexError:
|
||||
prev_p = None
|
||||
break
|
||||
if prev_p is not None:
|
||||
prev_p.has_children = True
|
||||
stack.append(p)
|
||||
p.depth = len(stack) - 1
|
||||
if limit is None:
|
||||
return queryset
|
||||
return list(filter(lambda p: p.depth <= limit, queryset))
|
||||
return self.extra(
|
||||
select={
|
||||
'parents': 'SELECT COUNT(U0."prefix") AS "c" '
|
||||
'FROM "ipam_prefix" U0 '
|
||||
'WHERE (U0."prefix" >> "ipam_prefix"."prefix" '
|
||||
'AND COALESCE(U0."vrf_id", 0) = COALESCE("ipam_prefix"."vrf_id", 0))',
|
||||
'children': 'SELECT COUNT(U1."prefix") AS "c" '
|
||||
'FROM "ipam_prefix" U1 '
|
||||
'WHERE (U1."prefix" << "ipam_prefix"."prefix" '
|
||||
'AND COALESCE(U1."vrf_id", 0) = COALESCE("ipam_prefix"."vrf_id", 0))',
|
||||
}
|
||||
)
|
||||
|
@ -221,9 +221,7 @@ class AggregateView(ObjectView):
|
||||
'site', 'role'
|
||||
).order_by(
|
||||
'prefix'
|
||||
).annotate_depth(
|
||||
limit=0
|
||||
)
|
||||
).annotate_tree()
|
||||
|
||||
# Add available prefixes to the table if requested
|
||||
if request.GET.get('show_available', 'true') == 'true':
|
||||
@ -326,11 +324,6 @@ class PrefixListView(ObjectListView):
|
||||
table = tables.PrefixDetailTable
|
||||
template_name = 'ipam/prefix_list.html'
|
||||
|
||||
def alter_queryset(self, request):
|
||||
# Show only top-level prefixes by default (unless searching)
|
||||
limit = None if request.GET.get('expand') or request.GET.get('q') else 0
|
||||
return self.queryset.annotate_depth(limit=limit)
|
||||
|
||||
|
||||
class PrefixView(ObjectView):
|
||||
queryset = Prefix.objects.prefetch_related('vrf', 'site__region', 'tenant__group', 'vlan__group', 'role')
|
||||
@ -353,7 +346,7 @@ class PrefixView(ObjectView):
|
||||
prefix__net_contains=str(prefix.prefix)
|
||||
).prefetch_related(
|
||||
'site', 'role'
|
||||
).annotate_depth()
|
||||
).annotate_tree()
|
||||
parent_prefix_table = tables.PrefixTable(list(parent_prefixes), orderable=False)
|
||||
parent_prefix_table.exclude = ('vrf',)
|
||||
|
||||
@ -386,7 +379,7 @@ class PrefixPrefixesView(ObjectView):
|
||||
# Child prefixes table
|
||||
child_prefixes = prefix.get_child_prefixes().restrict(request.user, 'view').prefetch_related(
|
||||
'site', 'vlan', 'role',
|
||||
).annotate_depth(limit=0)
|
||||
).annotate_tree()
|
||||
|
||||
# Add available prefixes to the table if requested
|
||||
if child_prefixes and request.GET.get('show_available', 'true') == 'true':
|
||||
|
Loading…
Reference in New Issue
Block a user