Есть ли у кого-нибудь эффективный алгоритм для извлечения всех предков из набора запросов 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) в дополнение, но я думаю, что это может стать огромным/медленным.