Does anybody have an efficient algorithm to retrieve all ancestors of an mptt queryset? The best I could think of so far is something like this:
def qs_ancestors(queryset):
if isinstance(queryset, EmptyQuerySet):
return queryset
queryset_aggs = queryset.values_list('tree_id', 'level').annotate(max_lft=Max('lft'), min_rght=Min('rght'))
new_queryset = queryset.none()
for tree_id, level, max_lft, min_rght in queryset_aggs:
ancestors = MyModel.objects.filter(
tree_id=tree_id,
level__lt=level,
lft__lte=max_lft,
rght__gte=min_rght,
)
new_queryset = ancestors | new_queryset
return new_queryset
There are two problems with this approach:
- It fails if there are branches that aren't next to each other (ie it doesn't really work)
- It is highly inefficient because it ends up have
number_of_trees*number_of_levels
clauses in the final query, which can get very large very fast
I am open to caching the ancestors somewhere else, but I cannot think of a way to do efficiently. I considered adding a field with a comma separated list of ancestor's ids and then doing a GROUP_CONCAT
(I am in MySQL) inside an extra, but I think that could get huge/slow.
obj.get_ancestors()
executes a query, does it not? So you end up with len(qs) + 1 queries without the optimization. – Imhoff