We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unable to fetch project updates in Up app
The current UAT build for the 3.13 release breaks the project updates download when Up data is loaded or refreshed:

https://github.com/akvo/akvo-rsr-up/issues/186

Environment:

Request Method: GET
Request URL: http://rsr.uat.akvo.org/rest/v1/project_up/2210/?format=xml&image_thumb_name=up&image_thumb_up_width=100

Django Version: 1.7.7
Python Version: 2.7.3
Installed Applications:
('nested_inline',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.humanize',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.webdesign',
'akvo.codelists',
'akvo.rsr',
'akvo.api',
'registration',
'template_utils',
'paypal.standard.ipn',
'sorl.thumbnail',
'django_counter',
'mollie.ideal',
'django_sorting',
'pagination',
'embed_video',
'django_markup',
'django_filters',
'tastypie',
'rest_framework',
'rest_framework.authtoken',
'rest_framework_swagger',
'pipeline',
'bootstrap3',
'rules',
'django_crontab',
'raven.contrib.django.raven_compat')
Installed Middleware:
('akvo.rsr.middleware.HostDispatchMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.http.ConditionalGetMiddleware',
'django_sorting.middleware.SortingMiddleware',
'pagination.middleware.PaginationMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'akvo.rsr.middleware.ExceptionLoggingMiddleware',
'akvo.rsr.middleware.RSRVersionHeaderMiddleware',
'django_statsd.middleware.GraphiteRequestTimingMiddleware',
'django_statsd.middleware.GraphiteMiddleware',
'django_statsd.middleware.TastyPieRequestTimingMiddleware')

Traceback:
File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response

response = wrapped_callback(request, callback_args, _callback_kwargs) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
return self.dispatch(request, args, *kwargs) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
return view_func(args, *kwargs) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
response = self.handle_exception(exc) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
response = handler(request, args, *kwargs) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/mixins.py" in retrieve
self.object = self.get_object() File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/generics.py" in get_object
queryset = self.filter_queryset(self.get_queryset()) File "/var/akvo/rsr/code/akvo/rest/views/project.py" in get_queryset
return super(ProjectViewSet, self).get_queryset() File "/var/akvo/rsr/code/akvo/rest/viewsets.py" in get_queryset
queryset = super(PublicProjectViewSet, self).get_queryset() File "/var/akvo/rsr/code/akvo/rest/viewsets.py" in get_queryset
queryset = queryset.filter(_*lookup) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/query.py" in filter
return self._filter_or_exclude(False, args, *kwargs) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/query.py" in _filter_or_exclude
clone.query.add_q(Q(args, *kwargs)) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in add_q
clause, require_inner = self._add_q(where_part, self.used_aliases) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in _add_q
current_negated=current_negated, connector=connector) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in build_filter
lookups, parts, reffed_aggregate = self.solve_lookup_type(arg) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in solve_lookup_type
_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta()) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in names_to_path
self.raise_field_error(opts, name) File "/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py" in raise_field_error
"Choices are: %s" % (name, ", ".join(available)))
Exception Type: FieldError at /rest/v1/project_up/2210/
Exception Value: Cannot resolve keyword u'image_thumb_name' into field. Choices are: background, benchmarks, budget, budget_items, capital_spend_percentage, categories, collaboration_type, comments, conditions, contacts, country_budget_items, country_budget_vocabulary, created_at, crsadd, currency, current_image, current_image_caption, current_image_credit, current_status, custom_fields, date_end_actual, date_end_planned, date_start_actual, date_start_planned, default_aid_type, default_finance_type, default_flow_type, default_tied_status, documents, donate_button, fss, funds, funds_needed, goals, goals_overview, hierarchy, humanitarian, humanitarian_scopes, iati_activity_id, iati_checks, iati_project_exports, iati_project_import_logs, iati_project_imports, iatiexport, iatiimportjob, id, invoices, is_impact_project, is_public, keywords, language, last_modified_at, last_update, last_update_id, legacy_data, links, locations, notes, partners, partnerships, paymentgatewayselector, planned_disbursements, policy_markers, primary_location, primary_location_id, primary_organisation, primary_organisation_id, project_plan, project_plan_summary, project_scope, project_updates, publishingstatus, recipient_countries, recipient_regions, related_projects, related_to_projects, results, sectors, status, subtitle, sustainability, target_group, title, transactions, validations


--- 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/viewsets.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Akvo RSR is covered by the GNU Affero General Public License.
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 from django.db.models.fields.related import ForeignKey, ForeignObject
8 
9 from akvo.rest.models import TastyTokenAuthentication
10 
11 from rest_framework import authentication, filters, permissions, viewsets
12 
13 from .filters import RSRGenericFilterBackend
14 
15 
16 class SafeMethodsPermissions(permissions.DjangoObjectPermissions):
17     """
18     Base class to allow any safe methods ('GET', 'OPTIONS' and 'HEAD') without needing to
19     authenticate.
20     """
21 
22     def has_permission(self, request, view):
23         if request.method in permissions.SAFE_METHODS:
24             return True
25         return super(SafeMethodsPermissions, self).has_permission(request, view)
26 
27 
28 class BaseRSRViewSet(viewsets.ModelViewSet):
29     """
30     Base class used for the view sets for RSR models. Provides unified auth and perms settings.
31     """
32     authentication_classes = (authentication.SessionAuthentication, TastyTokenAuthentication, )
33     permission_classes = (SafeMethodsPermissions, )
34     filter_backends = (filters.OrderingFilter, RSRGenericFilterBackend,)
35     ordering_fields = '__all__'
36 
37     def get_queryset(self):
38 
39         def django_filter_filters(request):
40             """
41             Support emulating the DjangoFilterBackend-based filtering that some views used to have
42             """
43             # query string keys reserved by the RSRGenericFilterBackend
44             qs_params = ['filter', 'exclude', 'select_related', 'prefetch_related', ]
45             # query string keys used by core DRF, OrderingFilter and Akvo custom views
46             exclude_params = ['limit', 'format', 'page', 'ordering', 'partner_type', 'sync_owner',
47                               'reporting_org']
48             filters = {}
49             for key in request.QUERY_PARAMS.keys():
50                 if key not in qs_params + exclude_params:
51                     filters.update({key: request.QUERY_PARAMS.get(key)})
52             return filters
53 
54         def get_lookups_from_filters(legacy_filters):
55             """
56             Cast the values in DjangoFilterBackend-styled query string filters to correct types to
57             be able to use them in regular queryset-filter() calls
58             """
59             # types of lookups supported by the views using DjangoFilterBackend
60             LEGACY_FIELD_LOOKUPS = ['exact', 'contains', 'icontains', 'gt', 'gte', 'lt',
61                                     'lte', ]
62             query_set_lookups = []
63             for key, value in legacy_filters.items():
64                 parts = key.split('__')
65                 if parts[-1] in LEGACY_FIELD_LOOKUPS:
66                     parts = parts[:-1]
67                     model = queryset.model
68                     for part in parts:
69                         field_object, related_model, direct, m2m = model._meta.get_field_by_name(
70                             part)
71                         if direct:
72                             if issubclass(field_object.__class__, ForeignObject):
73                                 model = field_object.related.parent_model
74                             else:
75                                 value = field_object.to_python(value)
76                                 break
77                         else:
78                             model = related_model
79                 query_set_lookups += [{key: value}]
80             return query_set_lookups
81 
82         queryset = super(BaseRSRViewSet, self).get_queryset()
83 
84         # support for old DjangoFilterBackend-based filtering
85         # find all "old styled" filters
86         legacy_filters = django_filter_filters(self.request)
87         # create lookup dicts from the filters found
88         lookups = get_lookups_from_filters(legacy_filters)
89         for lookup in lookups:
90             queryset = queryset.filter(**lookup)
91 
92         return queryset
93 
94 
95 class PublicProjectViewSet(BaseRSRViewSet):
96     """
97     Only public projects or objects related to public projects will be shown.
98     """
99     # project_relation is the default string for constructing a field lookup to the is_public field
100     # on the related Project. Override this in when the viewset is for a model that doesn't have a
101     # direct FK to Project or the FK field isn't named project. E.g. IndicatorViewSet:
102     #   project_relation = 'result__project__'
103     # The lookup is used to filter out objects associated with private projects, see below.
104     project_relation = 'project__'
105 
106     def get_queryset(self):
107 
108         request = self.request
109         user = request.user
110 
111         queryset = super(PublicProjectViewSet, self).get_queryset()
112 
113         def projects_filter_for_non_privileged_users(user, queryset):
114             # Construct the public projects filter field lookup.
115             project_filter = self.project_relation + 'is_public'
116 
117             # Filter the object list into two querysets;
118             # One where the related Projects are public and one where they are private
119             public_objects = queryset.filter(**{project_filter: True}).distinct()
120             private_objects = queryset.filter(**{project_filter: False}).distinct()
121 
122             # In case of an anonymous user, only return the public objects
123             if user.is_anonymous():
124                 queryset = public_objects
125 
126             # Otherwise, check to which objects the user has (change) permission
127             elif private_objects:
128                 permission = type(private_objects[0])._meta.db_table.replace('_', '.change_')
129                 permitted_obj_pks = []
130 
131                 # Loop through all 'private' objects to see if the user has permission to change
132                 # it. If so add its PK to the list of permitted objects.
133                 for obj in private_objects:
134                     if user.has_perm(permission, obj):
135                         permitted_obj_pks.append(obj.pk)
136 
137                 queryset = public_objects | queryset.filter(pk__in=permitted_obj_pks).distinct()
138 
139             return queryset
140 
141         # filter projects if user is "non-privileged"
142         if user.is_anonymous() or not (user.is_superuser or user.is_admin):
143             queryset = projects_filter_for_non_privileged_users(user, queryset)
144 
145         return queryset
146
```
--- 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()

```

diff --git a/akvo/rest/viewsets.py b/akvo/rest/viewsets.py
--- a/akvo/rest/viewsets.py
+++ b/akvo/rest/viewsets.py
@@ -44,10 +44,10 @@
             qs_params = ['filter', 'exclude', 'select_related', 'prefetch_related', ]
             # query string keys used by core DRF, OrderingFilter and Akvo custom views
             exclude_params = ['limit', 'format', 'page', 'ordering', 'partner_type', 'sync_owner',
-                              'reporting_org']
+                              'reporting_org', ]
             filters = {}
             for key in request.QUERY_PARAMS.keys():
-                if key not in qs_params + exclude_params:
+                if key not in qs_params + exclude_params and not key.startswith('image_thumb_'):
                     filters.update({key: request.QUERY_PARAMS.get(key)})
             return filters

{"golden_diff": "diff --git a/akvo/rest/viewsets.py b/akvo/rest/viewsets.py\n--- a/akvo/rest/viewsets.py\n+++ b/akvo/rest/viewsets.py\n@@ -44,10 +44,10 @@\n             qs_params = ['filter', 'exclude', 'select_related', 'prefetch_related', ]\n             # query string keys used by core DRF, OrderingFilter and Akvo custom views\n             exclude_params = ['limit', 'format', 'page', 'ordering', 'partner_type', 'sync_owner',\n-                              'reporting_org']\n+                              'reporting_org', ]\n             filters = {}\n             for key in request.QUERY_PARAMS.keys():\n-                if key not in qs_params + exclude_params:\n+                if key not in qs_params + exclude_params and not key.startswith('image_thumb_'):\n                     filters.update({key: request.QUERY_PARAMS.get(key)})\n             return filters\n", "issue": "Unable to fetch project updates in Up app\nThe current UAT build for the 3.13 release breaks the project updates download when Up data is loaded or refreshed:\n\nhttps://github.com/akvo/akvo-rsr-up/issues/186\n\nEnvironment:\n\nRequest Method: GET\nRequest URL: http://rsr.uat.akvo.org/rest/v1/project_up/2210/?format=xml&image_thumb_name=up&image_thumb_up_width=100\n\nDjango Version: 1.7.7\nPython Version: 2.7.3\nInstalled Applications:\n('nested_inline',\n'django.contrib.admin',\n'django.contrib.auth',\n'django.contrib.contenttypes',\n'django.contrib.humanize',\n'django.contrib.messages',\n'django.contrib.sessions',\n'django.contrib.staticfiles',\n'django.contrib.webdesign',\n'akvo.codelists',\n'akvo.rsr',\n'akvo.api',\n'registration',\n'template_utils',\n'paypal.standard.ipn',\n'sorl.thumbnail',\n'django_counter',\n'mollie.ideal',\n'django_sorting',\n'pagination',\n'embed_video',\n'django_markup',\n'django_filters',\n'tastypie',\n'rest_framework',\n'rest_framework.authtoken',\n'rest_framework_swagger',\n'pipeline',\n'bootstrap3',\n'rules',\n'django_crontab',\n'raven.contrib.django.raven_compat')\nInstalled Middleware:\n('akvo.rsr.middleware.HostDispatchMiddleware',\n'django.contrib.sessions.middleware.SessionMiddleware',\n'django.middleware.locale.LocaleMiddleware',\n'django.middleware.csrf.CsrfViewMiddleware',\n'django.middleware.http.ConditionalGetMiddleware',\n'django_sorting.middleware.SortingMiddleware',\n'pagination.middleware.PaginationMiddleware',\n'django.middleware.common.CommonMiddleware',\n'django.contrib.auth.middleware.AuthenticationMiddleware',\n'django.middleware.doc.XViewMiddleware',\n'django.contrib.messages.middleware.MessageMiddleware',\n'akvo.rsr.middleware.ExceptionLoggingMiddleware',\n'akvo.rsr.middleware.RSRVersionHeaderMiddleware',\n'django_statsd.middleware.GraphiteRequestTimingMiddleware',\n'django_statsd.middleware.GraphiteMiddleware',\n'django_statsd.middleware.TastyPieRequestTimingMiddleware')\n\nTraceback:\nFile \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py\" in get_response\n\nresponse = wrapped_callback(request, callback_args, _callback_kwargs) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/viewsets.py\" in view\nreturn self.dispatch(request, args, *kwargs) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py\" in wrapped_view\nreturn view_func(args, *kwargs) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/views.py\" in dispatch\nresponse = self.handle_exception(exc) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/views.py\" in dispatch\nresponse = handler(request, args, *kwargs) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/mixins.py\" in retrieve\nself.object = self.get_object() File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/rest_framework/generics.py\" in get_object\nqueryset = self.filter_queryset(self.get_queryset()) File \"/var/akvo/rsr/code/akvo/rest/views/project.py\" in get_queryset\nreturn super(ProjectViewSet, self).get_queryset() File \"/var/akvo/rsr/code/akvo/rest/viewsets.py\" in get_queryset\nqueryset = super(PublicProjectViewSet, self).get_queryset() File \"/var/akvo/rsr/code/akvo/rest/viewsets.py\" in get_queryset\nqueryset = queryset.filter(_*lookup) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/query.py\" in filter\nreturn self._filter_or_exclude(False, args, *kwargs) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/query.py\" in _filter_or_exclude\nclone.query.add_q(Q(args, *kwargs)) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in add_q\nclause, require_inner = self._add_q(where_part, self.used_aliases) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in _add_q\ncurrent_negated=current_negated, connector=connector) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in build_filter\nlookups, parts, reffed_aggregate = self.solve_lookup_type(arg) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in solve_lookup_type\n_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta()) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in names_to_path\nself.raise_field_error(opts, name) File \"/var/akvo/rsr/versions/deploy-RSR_Deploy-251/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\" in raise_field_error\n\"Choices are: %s\" % (name, \", \".join(available)))\nException Type: FieldError at /rest/v1/project_up/2210/\nException Value: Cannot resolve keyword u'image_thumb_name' into field. Choices are: background, benchmarks, budget, budget_items, capital_spend_percentage, categories, collaboration_type, comments, conditions, contacts, country_budget_items, country_budget_vocabulary, created_at, crsadd, currency, current_image, current_image_caption, current_image_credit, current_status, custom_fields, date_end_actual, date_end_planned, date_start_actual, date_start_planned, default_aid_type, default_finance_type, default_flow_type, default_tied_status, documents, donate_button, fss, funds, funds_needed, goals, goals_overview, hierarchy, humanitarian, humanitarian_scopes, iati_activity_id, iati_checks, iati_project_exports, iati_project_import_logs, iati_project_imports, iatiexport, iatiimportjob, id, invoices, is_impact_project, is_public, keywords, language, last_modified_at, last_update, last_update_id, legacy_data, links, locations, notes, partners, partnerships, paymentgatewayselector, planned_disbursements, policy_markers, primary_location, primary_location_id, primary_organisation, primary_organisation_id, project_plan, project_plan_summary, project_scope, project_updates, publishingstatus, recipient_countries, recipient_regions, related_projects, related_to_projects, results, sectors, status, subtitle, sustainability, target_group, title, transactions, validations\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Akvo RSR is covered by the GNU Affero General Public License.\n# See more details in the license.txt file located at the root folder of the Akvo RSR module.\n# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\nfrom django.db.models.fields.related import ForeignKey, ForeignObject\n\nfrom akvo.rest.models import TastyTokenAuthentication\n\nfrom rest_framework import authentication, filters, permissions, viewsets\n\nfrom .filters import RSRGenericFilterBackend\n\n\nclass SafeMethodsPermissions(permissions.DjangoObjectPermissions):\n    \"\"\"\n    Base class to allow any safe methods ('GET', 'OPTIONS' and 'HEAD') without needing to\n    authenticate.\n    \"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return super(SafeMethodsPermissions, self).has_permission(request, view)\n\n\nclass BaseRSRViewSet(viewsets.ModelViewSet):\n    \"\"\"\n    Base class used for the view sets for RSR models. Provides unified auth and perms settings.\n    \"\"\"\n    authentication_classes = (authentication.SessionAuthentication, TastyTokenAuthentication, )\n    permission_classes = (SafeMethodsPermissions, )\n    filter_backends = (filters.OrderingFilter, RSRGenericFilterBackend,)\n    ordering_fields = '__all__'\n\n    def get_queryset(self):\n\n        def django_filter_filters(request):\n            \"\"\"\n            Support emulating the DjangoFilterBackend-based filtering that some views used to have\n            \"\"\"\n            # query string keys reserved by the RSRGenericFilterBackend\n            qs_params = ['filter', 'exclude', 'select_related', 'prefetch_related', ]\n            # query string keys used by core DRF, OrderingFilter and Akvo custom views\n            exclude_params = ['limit', 'format', 'page', 'ordering', 'partner_type', 'sync_owner',\n                              'reporting_org']\n            filters = {}\n            for key in request.QUERY_PARAMS.keys():\n                if key not in qs_params + exclude_params:\n                    filters.update({key: request.QUERY_PARAMS.get(key)})\n            return filters\n\n        def get_lookups_from_filters(legacy_filters):\n            \"\"\"\n            Cast the values in DjangoFilterBackend-styled query string filters to correct types to\n            be able to use them in regular queryset-filter() calls\n            \"\"\"\n            # types of lookups supported by the views using DjangoFilterBackend\n            LEGACY_FIELD_LOOKUPS = ['exact', 'contains', 'icontains', 'gt', 'gte', 'lt',\n                                    'lte', ]\n            query_set_lookups = []\n            for key, value in legacy_filters.items():\n                parts = key.split('__')\n                if parts[-1] in LEGACY_FIELD_LOOKUPS:\n                    parts = parts[:-1]\n                    model = queryset.model\n                    for part in parts:\n                        field_object, related_model, direct, m2m = model._meta.get_field_by_name(\n                            part)\n                        if direct:\n                            if issubclass(field_object.__class__, ForeignObject):\n                                model = field_object.related.parent_model\n                            else:\n                                value = field_object.to_python(value)\n                                break\n                        else:\n                            model = related_model\n                query_set_lookups += [{key: value}]\n            return query_set_lookups\n\n        queryset = super(BaseRSRViewSet, self).get_queryset()\n\n        # support for old DjangoFilterBackend-based filtering\n        # find all \"old styled\" filters\n        legacy_filters = django_filter_filters(self.request)\n        # create lookup dicts from the filters found\n        lookups = get_lookups_from_filters(legacy_filters)\n        for lookup in lookups:\n            queryset = queryset.filter(**lookup)\n\n        return queryset\n\n\nclass PublicProjectViewSet(BaseRSRViewSet):\n    \"\"\"\n    Only public projects or objects related to public projects will be shown.\n    \"\"\"\n    # project_relation is the default string for constructing a field lookup to the is_public field\n    # on the related Project. Override this in when the viewset is for a model that doesn't have a\n    # direct FK to Project or the FK field isn't named project. E.g. IndicatorViewSet:\n    #   project_relation = 'result__project__'\n    # The lookup is used to filter out objects associated with private projects, see below.\n    project_relation = 'project__'\n\n    def get_queryset(self):\n\n        request = self.request\n        user = request.user\n\n        queryset = super(PublicProjectViewSet, self).get_queryset()\n\n        def projects_filter_for_non_privileged_users(user, queryset):\n            # Construct the public projects filter field lookup.\n            project_filter = self.project_relation + 'is_public'\n\n            # Filter the object list into two querysets;\n            # One where the related Projects are public and one where they are private\n            public_objects = queryset.filter(**{project_filter: True}).distinct()\n            private_objects = queryset.filter(**{project_filter: False}).distinct()\n\n            # In case of an anonymous user, only return the public objects\n            if user.is_anonymous():\n                queryset = public_objects\n\n            # Otherwise, check to which objects the user has (change) permission\n            elif private_objects:\n                permission = type(private_objects[0])._meta.db_table.replace('_', '.change_')\n                permitted_obj_pks = []\n\n                # Loop through all 'private' objects to see if the user has permission to change\n                # it. If so add its PK to the list of permitted objects.\n                for obj in private_objects:\n                    if user.has_perm(permission, obj):\n                        permitted_obj_pks.append(obj.pk)\n\n                queryset = public_objects | queryset.filter(pk__in=permitted_obj_pks).distinct()\n\n            return queryset\n\n        # filter projects if user is \"non-privileged\"\n        if user.is_anonymous() or not (user.is_superuser or user.is_admin):\n            queryset = projects_filter_for_non_privileged_users(user, queryset)\n\n        return queryset\n", "path": "akvo/rest/viewsets.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Akvo RSR is covered by the GNU Affero General Public License.\n# See more details in the license.txt file located at the root folder of the Akvo RSR module.\n# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\nfrom django.db.models.fields.related import ForeignKey, ForeignObject\n\nfrom akvo.rest.models import TastyTokenAuthentication\n\nfrom rest_framework import authentication, filters, permissions, viewsets\n\nfrom .filters import RSRGenericFilterBackend\n\n\nclass SafeMethodsPermissions(permissions.DjangoObjectPermissions):\n    \"\"\"\n    Base class to allow any safe methods ('GET', 'OPTIONS' and 'HEAD') without needing to\n    authenticate.\n    \"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return super(SafeMethodsPermissions, self).has_permission(request, view)\n\n\nclass BaseRSRViewSet(viewsets.ModelViewSet):\n    \"\"\"\n    Base class used for the view sets for RSR models. Provides unified auth and perms settings.\n    \"\"\"\n    authentication_classes = (authentication.SessionAuthentication, TastyTokenAuthentication, )\n    permission_classes = (SafeMethodsPermissions, )\n    filter_backends = (filters.OrderingFilter, RSRGenericFilterBackend,)\n    ordering_fields = '__all__'\n\n    def get_queryset(self):\n\n        def django_filter_filters(request):\n            \"\"\"\n            Support emulating the DjangoFilterBackend-based filtering that some views used to have\n            \"\"\"\n            # query string keys reserved by the RSRGenericFilterBackend\n            qs_params = ['filter', 'exclude', 'select_related', 'prefetch_related', ]\n            # query string keys used by core DRF, OrderingFilter and Akvo custom views\n            exclude_params = ['limit', 'format', 'page', 'ordering', 'partner_type', 'sync_owner',\n                              'reporting_org', ]\n            filters = {}\n            for key in request.QUERY_PARAMS.keys():\n                if key not in qs_params + exclude_params and not key.startswith('image_thumb_'):\n                    filters.update({key: request.QUERY_PARAMS.get(key)})\n            return filters\n\n        def get_lookups_from_filters(legacy_filters):\n            \"\"\"\n            Cast the values in DjangoFilterBackend-styled query string filters to correct types to\n            be able to use them in regular queryset-filter() calls\n            \"\"\"\n            # types of lookups supported by the views using DjangoFilterBackend\n            LEGACY_FIELD_LOOKUPS = ['exact', 'contains', 'icontains', 'gt', 'gte', 'lt',\n                                    'lte', ]\n            query_set_lookups = []\n            for key, value in legacy_filters.items():\n                parts = key.split('__')\n                if parts[-1] in LEGACY_FIELD_LOOKUPS:\n                    parts = parts[:-1]\n                    model = queryset.model\n                    for part in parts:\n                        field_object, related_model, direct, m2m = model._meta.get_field_by_name(\n                            part)\n                        if direct:\n                            if issubclass(field_object.__class__, ForeignObject):\n                                model = field_object.related.parent_model\n                            else:\n                                value = field_object.to_python(value)\n                                break\n                        else:\n                            model = related_model\n                query_set_lookups += [{key: value}]\n            return query_set_lookups\n\n        queryset = super(BaseRSRViewSet, self).get_queryset()\n\n        # support for old DjangoFilterBackend-based filtering\n        # find all \"old styled\" filters\n        legacy_filters = django_filter_filters(self.request)\n        # create lookup dicts from the filters found\n        lookups = get_lookups_from_filters(legacy_filters)\n        for lookup in lookups:\n            queryset = queryset.filter(**lookup)\n\n        return queryset\n\n\nclass PublicProjectViewSet(BaseRSRViewSet):\n    \"\"\"\n    Only public projects or objects related to public projects will be shown.\n    \"\"\"\n    # project_relation is the default string for constructing a field lookup to the is_public field\n    # on the related Project. Override this in when the viewset is for a model that doesn't have a\n    # direct FK to Project or the FK field isn't named project. E.g. IndicatorViewSet:\n    #   project_relation = 'result__project__'\n    # The lookup is used to filter out objects associated with private projects, see below.\n    project_relation = 'project__'\n\n    def get_queryset(self):\n\n        request = self.request\n        user = request.user\n\n        queryset = super(PublicProjectViewSet, self).get_queryset()\n\n        def projects_filter_for_non_privileged_users(user, queryset):\n            # Construct the public projects filter field lookup.\n            project_filter = self.project_relation + 'is_public'\n\n            # Filter the object list into two querysets;\n            # One where the related Projects are public and one where they are private\n            public_objects = queryset.filter(**{project_filter: True}).distinct()\n            private_objects = queryset.filter(**{project_filter: False}).distinct()\n\n            # In case of an anonymous user, only return the public objects\n            if user.is_anonymous():\n                queryset = public_objects\n\n            # Otherwise, check to which objects the user has (change) permission\n            elif private_objects:\n                permission = type(private_objects[0])._meta.db_table.replace('_', '.change_')\n                permitted_obj_pks = []\n\n                # Loop through all 'private' objects to see if the user has permission to change\n                # it. If so add its PK to the list of permitted objects.\n                for obj in private_objects:\n                    if user.has_perm(permission, obj):\n                        permitted_obj_pks.append(obj.pk)\n\n                queryset = public_objects | queryset.filter(pk__in=permitted_obj_pks).distinct()\n\n            return queryset\n\n        # filter projects if user is \"non-privileged\"\n        if user.is_anonymous() or not (user.is_superuser or user.is_admin):\n            queryset = projects_filter_for_non_privileged_users(user, queryset)\n\n        return queryset\n", "path": "akvo/rest/viewsets.py"}]}