|
1 | 1 | import logging |
2 | | -import uuid |
3 | 2 | from functools import reduce |
4 | 3 | from operator import or_ |
5 | 4 | from typing import Dict |
|
9 | 8 | from django.conf import settings |
10 | 9 | from django.db import IntegrityError |
11 | 10 | from django.db.models import Exists |
12 | | -from django.db.models import F |
13 | 11 | from django.db.models import OuterRef |
14 | 12 | from django.db.models import Q |
15 | 13 | from django.db.models import Subquery |
16 | | -from django.db.models import UUIDField |
17 | 14 | from django.db.models import Value |
18 | | -from django.db.models.functions import Cast |
19 | 15 | from django.db.models.functions import Coalesce |
20 | 16 | from django.http import HttpResponse |
21 | 17 | from django.http import HttpResponseNotFound |
|
25 | 21 | from django_cte import With |
26 | 22 | from django_filters.rest_framework import BooleanFilter |
27 | 23 | from django_filters.rest_framework import CharFilter |
28 | | -from kolibri_public.models import ContentNode as PublicContentNode |
29 | 24 | from le_utils.constants import content_kinds |
30 | 25 | from le_utils.constants import roles |
31 | 26 | from rest_framework import serializers |
@@ -744,20 +739,39 @@ def _get_channel_content_languages(self, channel_id, main_tree_id=None) -> List[ |
744 | 739 | if not channel_id: |
745 | 740 | return [] |
746 | 741 |
|
| 742 | + # determine the tree_id for the channel or from the root node (main_tree_id) |
| 743 | + tree_id = None |
| 744 | + if main_tree_id: |
| 745 | + tree_id = ( |
| 746 | + ContentNode.objects.filter(id=main_tree_id) |
| 747 | + .values_list("tree_id", flat=True) |
| 748 | + .first() |
| 749 | + ) |
| 750 | + elif not main_tree_id: |
| 751 | + try: |
| 752 | + tree_id = ( |
| 753 | + Channel.objects.filter(pk=channel_id) |
| 754 | + .values_list("main_tree__tree_id", flat=True) |
| 755 | + .first() |
| 756 | + ) |
| 757 | + except Exception as e: |
| 758 | + logging.error(str(e)) |
| 759 | + return [] |
| 760 | + |
747 | 761 | try: |
748 | | - ids_to_exclude = [main_tree_id] if main_tree_id else [] |
749 | | - node_ids_subquery = PublicContentNode.objects.filter( |
750 | | - channel_id=uuid.UUID(channel_id), |
751 | | - ).values_list("id", flat=True) |
752 | | - lang_ids = ContentNode.objects.filter( |
| 762 | + # performance: use a CTE to select just the tree's nodes, without default MPTT ordering, |
| 763 | + # then filter against the CTE to get the distinct language IDs |
| 764 | + cte = With( |
| 765 | + ContentNode.objects.filter(tree_id=tree_id) |
| 766 | + .values("id", "language_id") |
| 767 | + .order_by() |
| 768 | + ) |
| 769 | + qs = cte.queryset().with_cte(cte).filter( |
753 | 770 | language_id__isnull=False |
754 | | - ).annotate( |
755 | | - cast_node_id=Cast(F('node_id'), output_field=UUIDField()) |
756 | | - ).filter( |
757 | | - cast_node_id__in=Subquery(node_ids_subquery) |
758 | | - ).exclude( |
759 | | - id__in=ids_to_exclude |
760 | | - ).values_list('language_id', flat=True).distinct() |
| 771 | + ) |
| 772 | + if main_tree_id: |
| 773 | + qs = qs.exclude(id=main_tree_id) |
| 774 | + lang_ids = qs.values_list('language_id', flat=True).distinct() |
761 | 775 | unique_lang_ids = list(set(lang_ids)) |
762 | 776 | except Exception as e: |
763 | 777 | logging.error(str(e)) |
|
0 commit comments