Есть ли у кого-нибудь эффективный алгоритм для получения всех предков набора запросов mptt? Лучшее, что я мог придумать, это что-то вроде этого:
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
У этого подхода есть две проблемы:
- Не работает, если есть ветки, которые не расположены рядом (т.е. на самом деле не работает).
- Это очень неэффективно, потому что в конечном запросе у него есть
number_of_trees*number_of_levels
предложений, которые могут очень быстро стать очень большими.
Я открыт для кеширования предков где-нибудь еще, но я не могу придумать способ сделать это эффективно. Я подумал о том, чтобы добавить поле со списком идентификаторов предков, разделенных запятыми, а затем сделать GROUP_CONCAT
(я в MySQL) внутри дополнительного, но я думаю, что это может стать огромным / медленным.