prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Learn's Search is broken
  ## Summary
  
  * Search within Learn is currently broken on Develop.
  * See [triggerSearch()](https://github.com/learningequality/kolibri/blob/develop/kolibri/plugins/learn/assets/src/state/actions.js#L377)
  
  ## Exception
  
  `Exception Value: 'list' object has no attribute 'values_list'`
  
  ## How to reproduce
  
  1. Search for something within Learn
  
  ## Real-life consequences
  
  :rage4: 
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `kolibri/content/serializers.py`
  Content:
  ```
  1 from django.db.models import Manager
  2 from django.db.models.query import RawQuerySet
  3 from kolibri.content.models import AssessmentMetaData, ChannelMetadataCache, ContentNode, File
  4 from rest_framework import serializers
  5 
  6 from .content_db_router import default_database_is_attached, get_active_content_database
  7 
  8 
  9 class ChannelMetadataCacheSerializer(serializers.ModelSerializer):
  10 
  11     class Meta:
  12         model = ChannelMetadataCache
  13         fields = ('root_pk', 'id', 'name', 'description', 'author')
  14 
  15 
  16 class FileSerializer(serializers.ModelSerializer):
  17     storage_url = serializers.SerializerMethodField()
  18     preset = serializers.SerializerMethodField()
  19     download_url = serializers.SerializerMethodField()
  20 
  21     def get_storage_url(self, target_node):
  22         return target_node.get_storage_url()
  23 
  24     def get_preset(self, target_node):
  25         return target_node.get_preset()
  26 
  27     def get_download_url(self, target_node):
  28         return target_node.get_download_url()
  29 
  30     class Meta:
  31         model = File
  32         fields = ('storage_url', 'id', 'priority', 'checksum', 'available', 'file_size', 'extension', 'preset', 'lang',
  33                   'supplementary', 'thumbnail', 'download_url')
  34 
  35 
  36 class AssessmentMetaDataSerializer(serializers.ModelSerializer):
  37 
  38     assessment_item_ids = serializers.JSONField(default='[]')
  39     mastery_model = serializers.JSONField(default='{}')
  40 
  41     class Meta:
  42         model = AssessmentMetaData
  43         fields = ('assessment_item_ids', 'number_of_assessments', 'mastery_model', 'randomize', 'is_manipulable', )
  44 
  45 
  46 def get_progress_fraction(content_id, user):
  47     from kolibri.logger.models import ContentSummaryLog
  48     try:
  49         # add up all the progress for the logs, and divide by the total number of content nodes to get overall progress
  50         overall_progress = ContentSummaryLog.objects.get(user=user, content_id=content_id).progress
  51     except ContentSummaryLog.DoesNotExist:
  52         return None
  53     return round(overall_progress, 4)
  54 
  55 
  56 def get_progress_fractions(nodes, user):
  57     from kolibri.logger.models import ContentSummaryLog
  58     if isinstance(nodes, RawQuerySet):
  59         leaf_ids = [datum.content_id for datum in nodes]
  60     else:
  61         leaf_ids = nodes.values_list("content_id", flat=True)
  62 
  63     # get all summary logs for the current user that correspond to the descendant content nodes
  64     if default_database_is_attached():  # if possible, do a direct join between the content and default databases
  65         channel_alias = get_active_content_database()
  66         summary_logs = ContentSummaryLog.objects.using(channel_alias).filter(user=user, content_id__in=leaf_ids)
  67     else:  # otherwise, convert the leaf queryset into a flat list of ids and use that
  68         summary_logs = ContentSummaryLog.objects.filter(user=user, content_id__in=list(leaf_ids))
  69 
  70     # make a lookup dict for all logs to allow mapping from content_id to current progress
  71     overall_progress = {log['content_id']: round(log['progress'], 4) for log in summary_logs.values('content_id', 'progress')}
  72     return overall_progress
  73 
  74 
  75 class ContentNodeListSerializer(serializers.ListSerializer):
  76 
  77     def to_representation(self, data):
  78 
  79         if 'request' not in self.context or not self.context['request'].user.is_facility_user:
  80             progress_dict = {}
  81         else:
  82             user = self.context["request"].user
  83             progress_dict = get_progress_fractions(data, user)
  84 
  85         # Dealing with nested relationships, data can be a Manager,
  86         # so, first get a queryset from the Manager if needed
  87         iterable = data.all() if isinstance(data, Manager) else data
  88 
  89         return [
  90             self.child.to_representation(item, progress_dict.get(item.content_id)) for item in iterable
  91         ]
  92 
  93 
  94 class ContentNodeSerializer(serializers.ModelSerializer):
  95     parent = serializers.PrimaryKeyRelatedField(read_only=True)
  96     files = FileSerializer(many=True, read_only=True)
  97     assessmentmetadata = AssessmentMetaDataSerializer(read_only=True, allow_null=True, many=True)
  98     license = serializers.StringRelatedField(many=False)
  99     license_description = serializers.SerializerMethodField()
  100 
  101     def __init__(self, *args, **kwargs):
  102         # Instantiate the superclass normally
  103         super(ContentNodeSerializer, self).__init__(*args, **kwargs)
  104 
  105         # enable dynamic fields specification!
  106         if 'request' in self.context and self.context['request'].GET.get('fields', None):
  107             fields = self.context['request'].GET['fields'].split(',')
  108             # Drop any fields that are not specified in the `fields` argument.
  109             allowed = set(fields)
  110             existing = set(self.fields.keys())
  111             for field_name in existing - allowed:
  112                 self.fields.pop(field_name)
  113 
  114     def to_representation(self, instance, progress_fraction=None):
  115         if progress_fraction is None:
  116             if 'request' not in self.context or not self.context['request'].user.is_facility_user:
  117                 progress_fraction = 0
  118             else:
  119                 user = self.context["request"].user
  120                 progress_fraction = get_progress_fraction(instance.content_id, user)
  121         value = super(ContentNodeSerializer, self).to_representation(instance)
  122         value['progress_fraction'] = progress_fraction
  123         return value
  124 
  125     def get_license_description(self, target_node):
  126         if target_node.license_id:
  127             return target_node.license.license_description
  128         return ''
  129 
  130     class Meta:
  131         model = ContentNode
  132         fields = (
  133             'pk', 'content_id', 'title', 'description', 'kind', 'available', 'sort_order', 'license_owner',
  134             'license', 'license_description', 'files', 'parent', 'author',
  135             'assessmentmetadata',
  136         )
  137 
  138         list_serializer_class = ContentNodeListSerializer
  139
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/kolibri/content/serializers.py b/kolibri/content/serializers.py
  --- a/kolibri/content/serializers.py
  +++ b/kolibri/content/serializers.py
  @@ -55,7 +55,7 @@
   
   def get_progress_fractions(nodes, user):
       from kolibri.logger.models import ContentSummaryLog
  -    if isinstance(nodes, RawQuerySet):
  +    if isinstance(nodes, RawQuerySet) or isinstance(nodes, list):
           leaf_ids = [datum.content_id for datum in nodes]
       else:
           leaf_ids = nodes.values_list("content_id", flat=True)
  @@ -76,6 +76,9 @@
   
       def to_representation(self, data):
   
  +        if not data:
  +            return data
  +
           if 'request' not in self.context or not self.context['request'].user.is_facility_user:
               progress_dict = {}
           else:
  
verification_info: {"golden_diff": "diff --git a/kolibri/content/serializers.py b/kolibri/content/serializers.py\n--- a/kolibri/content/serializers.py\n+++ b/kolibri/content/serializers.py\n@@ -55,7 +55,7 @@\n \n def get_progress_fractions(nodes, user):\n     from kolibri.logger.models import ContentSummaryLog\n-    if isinstance(nodes, RawQuerySet):\n+    if isinstance(nodes, RawQuerySet) or isinstance(nodes, list):\n         leaf_ids = [datum.content_id for datum in nodes]\n     else:\n         leaf_ids = nodes.values_list(\"content_id\", flat=True)\n@@ -76,6 +76,9 @@\n \n     def to_representation(self, data):\n \n+        if not data:\n+            return data\n+\n         if 'request' not in self.context or not self.context['request'].user.is_facility_user:\n             progress_dict = {}\n         else:\n", "issue": "Learn's Search is broken\n## Summary\r\n\r\n* Search within Learn is currently broken on Develop.\r\n* See [triggerSearch()](https://github.com/learningequality/kolibri/blob/develop/kolibri/plugins/learn/assets/src/state/actions.js#L377)\r\n\r\n## Exception\r\n\r\n`Exception Value: 'list' object has no attribute 'values_list'`\r\n\r\n## How to reproduce\r\n\r\n1. Search for something within Learn\r\n\r\n## Real-life consequences\r\n\r\n:rage4: \n", "before_files": [{"content": "from django.db.models import Manager\nfrom django.db.models.query import RawQuerySet\nfrom kolibri.content.models import AssessmentMetaData, ChannelMetadataCache, ContentNode, File\nfrom rest_framework import serializers\n\nfrom .content_db_router import default_database_is_attached, get_active_content_database\n\n\nclass ChannelMetadataCacheSerializer(serializers.ModelSerializer):\n\n    class Meta:\n        model = ChannelMetadataCache\n        fields = ('root_pk', 'id', 'name', 'description', 'author')\n\n\nclass FileSerializer(serializers.ModelSerializer):\n    storage_url = serializers.SerializerMethodField()\n    preset = serializers.SerializerMethodField()\n    download_url = serializers.SerializerMethodField()\n\n    def get_storage_url(self, target_node):\n        return target_node.get_storage_url()\n\n    def get_preset(self, target_node):\n        return target_node.get_preset()\n\n    def get_download_url(self, target_node):\n        return target_node.get_download_url()\n\n    class Meta:\n        model = File\n        fields = ('storage_url', 'id', 'priority', 'checksum', 'available', 'file_size', 'extension', 'preset', 'lang',\n                  'supplementary', 'thumbnail', 'download_url')\n\n\nclass AssessmentMetaDataSerializer(serializers.ModelSerializer):\n\n    assessment_item_ids = serializers.JSONField(default='[]')\n    mastery_model = serializers.JSONField(default='{}')\n\n    class Meta:\n        model = AssessmentMetaData\n        fields = ('assessment_item_ids', 'number_of_assessments', 'mastery_model', 'randomize', 'is_manipulable', )\n\n\ndef get_progress_fraction(content_id, user):\n    from kolibri.logger.models import ContentSummaryLog\n    try:\n        # add up all the progress for the logs, and divide by the total number of content nodes to get overall progress\n        overall_progress = ContentSummaryLog.objects.get(user=user, content_id=content_id).progress\n    except ContentSummaryLog.DoesNotExist:\n        return None\n    return round(overall_progress, 4)\n\n\ndef get_progress_fractions(nodes, user):\n    from kolibri.logger.models import ContentSummaryLog\n    if isinstance(nodes, RawQuerySet):\n        leaf_ids = [datum.content_id for datum in nodes]\n    else:\n        leaf_ids = nodes.values_list(\"content_id\", flat=True)\n\n    # get all summary logs for the current user that correspond to the descendant content nodes\n    if default_database_is_attached():  # if possible, do a direct join between the content and default databases\n        channel_alias = get_active_content_database()\n        summary_logs = ContentSummaryLog.objects.using(channel_alias).filter(user=user, content_id__in=leaf_ids)\n    else:  # otherwise, convert the leaf queryset into a flat list of ids and use that\n        summary_logs = ContentSummaryLog.objects.filter(user=user, content_id__in=list(leaf_ids))\n\n    # make a lookup dict for all logs to allow mapping from content_id to current progress\n    overall_progress = {log['content_id']: round(log['progress'], 4) for log in summary_logs.values('content_id', 'progress')}\n    return overall_progress\n\n\nclass ContentNodeListSerializer(serializers.ListSerializer):\n\n    def to_representation(self, data):\n\n        if 'request' not in self.context or not self.context['request'].user.is_facility_user:\n            progress_dict = {}\n        else:\n            user = self.context[\"request\"].user\n            progress_dict = get_progress_fractions(data, user)\n\n        # Dealing with nested relationships, data can be a Manager,\n        # so, first get a queryset from the Manager if needed\n        iterable = data.all() if isinstance(data, Manager) else data\n\n        return [\n            self.child.to_representation(item, progress_dict.get(item.content_id)) for item in iterable\n        ]\n\n\nclass ContentNodeSerializer(serializers.ModelSerializer):\n    parent = serializers.PrimaryKeyRelatedField(read_only=True)\n    files = FileSerializer(many=True, read_only=True)\n    assessmentmetadata = AssessmentMetaDataSerializer(read_only=True, allow_null=True, many=True)\n    license = serializers.StringRelatedField(many=False)\n    license_description = serializers.SerializerMethodField()\n\n    def __init__(self, *args, **kwargs):\n        # Instantiate the superclass normally\n        super(ContentNodeSerializer, self).__init__(*args, **kwargs)\n\n        # enable dynamic fields specification!\n        if 'request' in self.context and self.context['request'].GET.get('fields', None):\n            fields = self.context['request'].GET['fields'].split(',')\n            # Drop any fields that are not specified in the `fields` argument.\n            allowed = set(fields)\n            existing = set(self.fields.keys())\n            for field_name in existing - allowed:\n                self.fields.pop(field_name)\n\n    def to_representation(self, instance, progress_fraction=None):\n        if progress_fraction is None:\n            if 'request' not in self.context or not self.context['request'].user.is_facility_user:\n                progress_fraction = 0\n            else:\n                user = self.context[\"request\"].user\n                progress_fraction = get_progress_fraction(instance.content_id, user)\n        value = super(ContentNodeSerializer, self).to_representation(instance)\n        value['progress_fraction'] = progress_fraction\n        return value\n\n    def get_license_description(self, target_node):\n        if target_node.license_id:\n            return target_node.license.license_description\n        return ''\n\n    class Meta:\n        model = ContentNode\n        fields = (\n            'pk', 'content_id', 'title', 'description', 'kind', 'available', 'sort_order', 'license_owner',\n            'license', 'license_description', 'files', 'parent', 'author',\n            'assessmentmetadata',\n        )\n\n        list_serializer_class = ContentNodeListSerializer\n", "path": "kolibri/content/serializers.py"}], "after_files": [{"content": "from django.db.models import Manager\nfrom django.db.models.query import RawQuerySet\nfrom kolibri.content.models import AssessmentMetaData, ChannelMetadataCache, ContentNode, File\nfrom rest_framework import serializers\n\nfrom .content_db_router import default_database_is_attached, get_active_content_database\n\n\nclass ChannelMetadataCacheSerializer(serializers.ModelSerializer):\n\n    class Meta:\n        model = ChannelMetadataCache\n        fields = ('root_pk', 'id', 'name', 'description', 'author')\n\n\nclass FileSerializer(serializers.ModelSerializer):\n    storage_url = serializers.SerializerMethodField()\n    preset = serializers.SerializerMethodField()\n    download_url = serializers.SerializerMethodField()\n\n    def get_storage_url(self, target_node):\n        return target_node.get_storage_url()\n\n    def get_preset(self, target_node):\n        return target_node.get_preset()\n\n    def get_download_url(self, target_node):\n        return target_node.get_download_url()\n\n    class Meta:\n        model = File\n        fields = ('storage_url', 'id', 'priority', 'checksum', 'available', 'file_size', 'extension', 'preset', 'lang',\n                  'supplementary', 'thumbnail', 'download_url')\n\n\nclass AssessmentMetaDataSerializer(serializers.ModelSerializer):\n\n    assessment_item_ids = serializers.JSONField(default='[]')\n    mastery_model = serializers.JSONField(default='{}')\n\n    class Meta:\n        model = AssessmentMetaData\n        fields = ('assessment_item_ids', 'number_of_assessments', 'mastery_model', 'randomize', 'is_manipulable', )\n\n\ndef get_progress_fraction(content_id, user):\n    from kolibri.logger.models import ContentSummaryLog\n    try:\n        # add up all the progress for the logs, and divide by the total number of content nodes to get overall progress\n        overall_progress = ContentSummaryLog.objects.get(user=user, content_id=content_id).progress\n    except ContentSummaryLog.DoesNotExist:\n        return None\n    return round(overall_progress, 4)\n\n\ndef get_progress_fractions(nodes, user):\n    from kolibri.logger.models import ContentSummaryLog\n    if isinstance(nodes, RawQuerySet) or isinstance(nodes, list):\n        leaf_ids = [datum.content_id for datum in nodes]\n    else:\n        leaf_ids = nodes.values_list(\"content_id\", flat=True)\n\n    # get all summary logs for the current user that correspond to the descendant content nodes\n    if default_database_is_attached():  # if possible, do a direct join between the content and default databases\n        channel_alias = get_active_content_database()\n        summary_logs = ContentSummaryLog.objects.using(channel_alias).filter(user=user, content_id__in=leaf_ids)\n    else:  # otherwise, convert the leaf queryset into a flat list of ids and use that\n        summary_logs = ContentSummaryLog.objects.filter(user=user, content_id__in=list(leaf_ids))\n\n    # make a lookup dict for all logs to allow mapping from content_id to current progress\n    overall_progress = {log['content_id']: round(log['progress'], 4) for log in summary_logs.values('content_id', 'progress')}\n    return overall_progress\n\n\nclass ContentNodeListSerializer(serializers.ListSerializer):\n\n    def to_representation(self, data):\n\n        if not data:\n            return data\n\n        if 'request' not in self.context or not self.context['request'].user.is_facility_user:\n            progress_dict = {}\n        else:\n            user = self.context[\"request\"].user\n            progress_dict = get_progress_fractions(data, user)\n\n        # Dealing with nested relationships, data can be a Manager,\n        # so, first get a queryset from the Manager if needed\n        iterable = data.all() if isinstance(data, Manager) else data\n\n        return [\n            self.child.to_representation(item, progress_dict.get(item.content_id)) for item in iterable\n        ]\n\n\nclass ContentNodeSerializer(serializers.ModelSerializer):\n    parent = serializers.PrimaryKeyRelatedField(read_only=True)\n    files = FileSerializer(many=True, read_only=True)\n    assessmentmetadata = AssessmentMetaDataSerializer(read_only=True, allow_null=True, many=True)\n    license = serializers.StringRelatedField(many=False)\n    license_description = serializers.SerializerMethodField()\n\n    def __init__(self, *args, **kwargs):\n        # Instantiate the superclass normally\n        super(ContentNodeSerializer, self).__init__(*args, **kwargs)\n\n        # enable dynamic fields specification!\n        if 'request' in self.context and self.context['request'].GET.get('fields', None):\n            fields = self.context['request'].GET['fields'].split(',')\n            # Drop any fields that are not specified in the `fields` argument.\n            allowed = set(fields)\n            existing = set(self.fields.keys())\n            for field_name in existing - allowed:\n                self.fields.pop(field_name)\n\n    def to_representation(self, instance, progress_fraction=None):\n        if progress_fraction is None:\n            if 'request' not in self.context or not self.context['request'].user.is_facility_user:\n                progress_fraction = 0\n            else:\n                user = self.context[\"request\"].user\n                progress_fraction = get_progress_fraction(instance.content_id, user)\n        value = super(ContentNodeSerializer, self).to_representation(instance)\n        value['progress_fraction'] = progress_fraction\n        return value\n\n    def get_license_description(self, target_node):\n        if target_node.license_id:\n            return target_node.license.license_description\n        return ''\n\n    class Meta:\n        model = ContentNode\n        fields = (\n            'pk', 'content_id', 'title', 'description', 'kind', 'available', 'sort_order', 'license_owner',\n            'license', 'license_description', 'files', 'parent', 'author',\n            'assessmentmetadata',\n        )\n\n        list_serializer_class = ContentNodeListSerializer\n", "path": "kolibri/content/serializers.py"}]}