prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  REST API: project_extra with organisation filter gives duplicates
  The `project_extra` REST API endpoint shows duplicate projects when it is filtered on organisation.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `akvo/rest/views/project.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 """Akvo RSR is covered by the GNU Affero General Public License.
  3 
  4 See more details in the license.txt file located at the root folder of the Akvo RSR module.
  5 For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
  6 """
  7 
  8 from akvo.rest.serializers.project import ProjectUpSerializer
  9 from akvo.rsr.models import Project, PublishingStatus
  10 from ..serializers import ProjectSerializer, ProjectExtraSerializer
  11 from ..viewsets import BaseRSRViewSet
  12 
  13 
  14 class ProjectViewSet(BaseRSRViewSet):
  15 
  16     """
  17     Viewset providing Project data.
  18 
  19     Allowed parameters are:
  20     __limit__ (default 30, max 100),
  21     __title__ (exact or icontains),
  22     __subtitle__ (exact or icontains),
  23     __status__,
  24     __language__,
  25     __currency__,
  26     __date_start_planned__ (exact, gt, gte, lt or lte),
  27     __date_start_actual__ (exact, gt, gte, lt or lte),
  28     __date_end_planned__ (exact, gt, gte, lt or lte),
  29     __date_end_actual__ (exact, gt, gte, lt or lte),
  30     __created_at__ (exact, gt, gte, lt or lte),
  31     __last_modified_at__ (exact, gt, gte, lt or lte),
  32     __sync_owner__,
  33     __iati_activity_id__ (exact or icontains),
  34     __hierarchy__,
  35     __project_scope__,
  36     __collaboration_type__,
  37     __default_aid_type__,
  38     __default_finance_type__,
  39     __default_flow_type__,
  40     __default_tied_status__,
  41     __budget__ (exact, gt, gte, lt or lte),
  42     __funds__ (exact, gt, gte, lt or lte),
  43     __funds_needed__ (exact, gt, gte, lt or lte),
  44     __categories__ (exact, in),
  45     __partners__ (exact, in),
  46     __keywords__ (exact, in), and
  47     __publishingstatus\__status__.
  48     """
  49     queryset = Project.objects.select_related(
  50         'publishingstatus'
  51         ).prefetch_related(
  52             'categories',
  53             'keywords',
  54             'partners')
  55 
  56     serializer_class = ProjectSerializer
  57     filter_fields = {
  58         'title': ['exact', 'icontains'],
  59         'subtitle': ['exact', 'icontains'],
  60         'status': ['exact', ],
  61         'language': ['exact', ],
  62         'currency': ['exact', ],
  63         'date_start_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  64         'date_start_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  65         'date_end_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  66         'date_end_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  67         'created_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  68         'last_modified_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  69         'iati_activity_id': ['exact', 'icontains', ],
  70         'hierarchy': ['exact', ],
  71         'project_scope': ['exact', ],
  72         'collaboration_type': ['exact', ],
  73         'default_aid_type': ['exact', ],
  74         'default_finance_type': ['exact', ],
  75         'default_flow_type': ['exact', ],
  76         'default_tied_status': ['exact', ],
  77         'budget': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  78         'funds': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  79         'funds_needed': ['exact', 'gt', 'gte', 'lt', 'lte', ],
  80         'categories': ['exact', 'in', ],
  81         'partners': ['exact', 'in', ],
  82         'keywords': ['exact', 'in', ],
  83         'publishingstatus__status': ['exact', ],
  84     }
  85 
  86     def get_queryset(self):
  87         """
  88         Allow custom filter for sync_owner, since this field has been replaced by the
  89         reporting org partnership.
  90         """
  91         queryset = self.queryset
  92         sync_owner = self.request.QUERY_PARAMS.get('sync_owner', None)
  93         if sync_owner:
  94             queryset = queryset.filter(partnerships__iati_organisation_role=101,
  95                                        partnerships__organisation__pk=sync_owner)
  96         return queryset
  97 
  98 
  99 class ProjectExtraViewSet(ProjectViewSet):
  100 
  101     """
  102     Viewset providing extra Project data.
  103 
  104     Allowed parameters are:
  105     __limit__ (default 30, max 100),
  106     __partnerships\__organisation__ (filter on organisation ID), and
  107     __publishingstatus\__status__ (filter on publishing status)
  108     """
  109 
  110     queryset = Project.objects.select_related(
  111         'publishing_status').prefetch_related(
  112             'sectors', 'partnerships')
  113     serializer_class = ProjectExtraSerializer
  114     paginate_by_param = 'limit'
  115     filter_fields = ('partnerships__organisation', 'publishingstatus__status')
  116 
  117 
  118 class ProjectUpViewSet(ProjectViewSet):
  119 
  120     """
  121     Viewset providing extra data and limited filtering for Up in one go.
  122 
  123     Allowed parameters are:
  124     __limit__ (default 30, max 100),
  125     __partnerships\__organisation__ (filter on organisation ID), and
  126     __publishingstatus\__status__ (filter on publishing status)
  127     """
  128 
  129     queryset = Project.objects.select_related(
  130         'primary_location',
  131         'updates',
  132         'publishingstatus'
  133         ).prefetch_related(
  134             'categories',
  135             'keywords',
  136             'partners')
  137     serializer_class = ProjectUpSerializer
  138     paginate_by_param = 'limit'
  139     max_paginate_by = 100
  140     filter_fields = ('partnerships__organisation', 'publishingstatus__status')
  141
  ```
  --- 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/akvo/rest/views/project.py b/akvo/rest/views/project.py
  --- a/akvo/rest/views/project.py
  +++ b/akvo/rest/views/project.py
  @@ -93,7 +93,7 @@
           if sync_owner:
               queryset = queryset.filter(partnerships__iati_organisation_role=101,
                                          partnerships__organisation__pk=sync_owner)
  -        return queryset
  +        return queryset.distinct()
   
   
   class ProjectExtraViewSet(ProjectViewSet):
  
verification_info: {"golden_diff": "diff --git a/akvo/rest/views/project.py b/akvo/rest/views/project.py\n--- a/akvo/rest/views/project.py\n+++ b/akvo/rest/views/project.py\n@@ -93,7 +93,7 @@\n         if sync_owner:\n             queryset = queryset.filter(partnerships__iati_organisation_role=101,\n                                        partnerships__organisation__pk=sync_owner)\n-        return queryset\n+        return queryset.distinct()\n \n \n class ProjectExtraViewSet(ProjectViewSet):\n", "issue": "REST API: project_extra with organisation filter gives duplicates\nThe `project_extra` REST API endpoint shows duplicate projects when it is filtered on organisation.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the Akvo RSR module.\nFor additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nfrom akvo.rest.serializers.project import ProjectUpSerializer\nfrom akvo.rsr.models import Project, PublishingStatus\nfrom ..serializers import ProjectSerializer, ProjectExtraSerializer\nfrom ..viewsets import BaseRSRViewSet\n\n\nclass ProjectViewSet(BaseRSRViewSet):\n\n    \"\"\"\n    Viewset providing Project data.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __title__ (exact or icontains),\n    __subtitle__ (exact or icontains),\n    __status__,\n    __language__,\n    __currency__,\n    __date_start_planned__ (exact, gt, gte, lt or lte),\n    __date_start_actual__ (exact, gt, gte, lt or lte),\n    __date_end_planned__ (exact, gt, gte, lt or lte),\n    __date_end_actual__ (exact, gt, gte, lt or lte),\n    __created_at__ (exact, gt, gte, lt or lte),\n    __last_modified_at__ (exact, gt, gte, lt or lte),\n    __sync_owner__,\n    __iati_activity_id__ (exact or icontains),\n    __hierarchy__,\n    __project_scope__,\n    __collaboration_type__,\n    __default_aid_type__,\n    __default_finance_type__,\n    __default_flow_type__,\n    __default_tied_status__,\n    __budget__ (exact, gt, gte, lt or lte),\n    __funds__ (exact, gt, gte, lt or lte),\n    __funds_needed__ (exact, gt, gte, lt or lte),\n    __categories__ (exact, in),\n    __partners__ (exact, in),\n    __keywords__ (exact, in), and\n    __publishingstatus\\__status__.\n    \"\"\"\n    queryset = Project.objects.select_related(\n        'publishingstatus'\n        ).prefetch_related(\n            'categories',\n            'keywords',\n            'partners')\n\n    serializer_class = ProjectSerializer\n    filter_fields = {\n        'title': ['exact', 'icontains'],\n        'subtitle': ['exact', 'icontains'],\n        'status': ['exact', ],\n        'language': ['exact', ],\n        'currency': ['exact', ],\n        'date_start_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_start_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_end_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_end_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'created_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'last_modified_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'iati_activity_id': ['exact', 'icontains', ],\n        'hierarchy': ['exact', ],\n        'project_scope': ['exact', ],\n        'collaboration_type': ['exact', ],\n        'default_aid_type': ['exact', ],\n        'default_finance_type': ['exact', ],\n        'default_flow_type': ['exact', ],\n        'default_tied_status': ['exact', ],\n        'budget': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'funds': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'funds_needed': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'categories': ['exact', 'in', ],\n        'partners': ['exact', 'in', ],\n        'keywords': ['exact', 'in', ],\n        'publishingstatus__status': ['exact', ],\n    }\n\n    def get_queryset(self):\n        \"\"\"\n        Allow custom filter for sync_owner, since this field has been replaced by the\n        reporting org partnership.\n        \"\"\"\n        queryset = self.queryset\n        sync_owner = self.request.QUERY_PARAMS.get('sync_owner', None)\n        if sync_owner:\n            queryset = queryset.filter(partnerships__iati_organisation_role=101,\n                                       partnerships__organisation__pk=sync_owner)\n        return queryset\n\n\nclass ProjectExtraViewSet(ProjectViewSet):\n\n    \"\"\"\n    Viewset providing extra Project data.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __partnerships\\__organisation__ (filter on organisation ID), and\n    __publishingstatus\\__status__ (filter on publishing status)\n    \"\"\"\n\n    queryset = Project.objects.select_related(\n        'publishing_status').prefetch_related(\n            'sectors', 'partnerships')\n    serializer_class = ProjectExtraSerializer\n    paginate_by_param = 'limit'\n    filter_fields = ('partnerships__organisation', 'publishingstatus__status')\n\n\nclass ProjectUpViewSet(ProjectViewSet):\n\n    \"\"\"\n    Viewset providing extra data and limited filtering for Up in one go.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __partnerships\\__organisation__ (filter on organisation ID), and\n    __publishingstatus\\__status__ (filter on publishing status)\n    \"\"\"\n\n    queryset = Project.objects.select_related(\n        'primary_location',\n        'updates',\n        'publishingstatus'\n        ).prefetch_related(\n            'categories',\n            'keywords',\n            'partners')\n    serializer_class = ProjectUpSerializer\n    paginate_by_param = 'limit'\n    max_paginate_by = 100\n    filter_fields = ('partnerships__organisation', 'publishingstatus__status')\n", "path": "akvo/rest/views/project.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Akvo RSR is covered by the GNU Affero General Public License.\n\nSee more details in the license.txt file located at the root folder of the Akvo RSR module.\nFor additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\"\"\"\n\nfrom akvo.rest.serializers.project import ProjectUpSerializer\nfrom akvo.rsr.models import Project, PublishingStatus\nfrom ..serializers import ProjectSerializer, ProjectExtraSerializer\nfrom ..viewsets import BaseRSRViewSet\n\n\nclass ProjectViewSet(BaseRSRViewSet):\n\n    \"\"\"\n    Viewset providing Project data.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __title__ (exact or icontains),\n    __subtitle__ (exact or icontains),\n    __status__,\n    __language__,\n    __currency__,\n    __date_start_planned__ (exact, gt, gte, lt or lte),\n    __date_start_actual__ (exact, gt, gte, lt or lte),\n    __date_end_planned__ (exact, gt, gte, lt or lte),\n    __date_end_actual__ (exact, gt, gte, lt or lte),\n    __created_at__ (exact, gt, gte, lt or lte),\n    __last_modified_at__ (exact, gt, gte, lt or lte),\n    __sync_owner__,\n    __iati_activity_id__ (exact or icontains),\n    __hierarchy__,\n    __project_scope__,\n    __collaboration_type__,\n    __default_aid_type__,\n    __default_finance_type__,\n    __default_flow_type__,\n    __default_tied_status__,\n    __budget__ (exact, gt, gte, lt or lte),\n    __funds__ (exact, gt, gte, lt or lte),\n    __funds_needed__ (exact, gt, gte, lt or lte),\n    __categories__ (exact, in),\n    __partners__ (exact, in),\n    __keywords__ (exact, in), and\n    __publishingstatus\\__status__.\n    \"\"\"\n    queryset = Project.objects.select_related(\n        'publishingstatus'\n        ).prefetch_related(\n            'categories',\n            'keywords',\n            'partners')\n\n    serializer_class = ProjectSerializer\n    filter_fields = {\n        'title': ['exact', 'icontains'],\n        'subtitle': ['exact', 'icontains'],\n        'status': ['exact', ],\n        'language': ['exact', ],\n        'currency': ['exact', ],\n        'date_start_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_start_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_end_planned': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'date_end_actual': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'created_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'last_modified_at': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'iati_activity_id': ['exact', 'icontains', ],\n        'hierarchy': ['exact', ],\n        'project_scope': ['exact', ],\n        'collaboration_type': ['exact', ],\n        'default_aid_type': ['exact', ],\n        'default_finance_type': ['exact', ],\n        'default_flow_type': ['exact', ],\n        'default_tied_status': ['exact', ],\n        'budget': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'funds': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'funds_needed': ['exact', 'gt', 'gte', 'lt', 'lte', ],\n        'categories': ['exact', 'in', ],\n        'partners': ['exact', 'in', ],\n        'keywords': ['exact', 'in', ],\n        'publishingstatus__status': ['exact', ],\n    }\n\n    def get_queryset(self):\n        \"\"\"\n        Allow custom filter for sync_owner, since this field has been replaced by the\n        reporting org partnership.\n        \"\"\"\n        queryset = self.queryset\n        sync_owner = self.request.QUERY_PARAMS.get('sync_owner', None)\n        if sync_owner:\n            queryset = queryset.filter(partnerships__iati_organisation_role=101,\n                                       partnerships__organisation__pk=sync_owner)\n        return queryset.distinct()\n\n\nclass ProjectExtraViewSet(ProjectViewSet):\n\n    \"\"\"\n    Viewset providing extra Project data.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __partnerships\\__organisation__ (filter on organisation ID), and\n    __publishingstatus\\__status__ (filter on publishing status)\n    \"\"\"\n\n    queryset = Project.objects.select_related(\n        'publishing_status').prefetch_related(\n            'sectors', 'partnerships')\n    serializer_class = ProjectExtraSerializer\n    paginate_by_param = 'limit'\n    filter_fields = ('partnerships__organisation', 'publishingstatus__status')\n\n\nclass ProjectUpViewSet(ProjectViewSet):\n\n    \"\"\"\n    Viewset providing extra data and limited filtering for Up in one go.\n\n    Allowed parameters are:\n    __limit__ (default 30, max 100),\n    __partnerships\\__organisation__ (filter on organisation ID), and\n    __publishingstatus\\__status__ (filter on publishing status)\n    \"\"\"\n\n    queryset = Project.objects.select_related(\n        'primary_location',\n        'updates',\n        'publishingstatus'\n        ).prefetch_related(\n            'categories',\n            'keywords',\n            'partners')\n    serializer_class = ProjectUpSerializer\n    paginate_by_param = 'limit'\n    max_paginate_by = 100\n    filter_fields = ('partnerships__organisation', 'publishingstatus__status')\n", "path": "akvo/rest/views/project.py"}]}