[RFC 09/11] REST: Add query parameters to filter patches by

Andy Doan andy.doan at linaro.org
Sat Apr 16 04:24:05 AEST 2016


This adds generic filtering support to the PatchworkViewSet as well as
useful filtering options for listing patches.

DRF has some filter capabilities, but they can really slow down the web
interface for large data sets and are a little complex. This approach is
pretty simple and works efficiently.

The "options" method is now overridden to show the user available
filters when supported.

Signed-off-by: Andy Doan <andy.doan at linaro.org>
---
 patchwork/tests/test_rest_api.py | 24 ++++++++++++++++++++++++
 patchwork/views/rest_api.py      | 38 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py
index fe21fcf..037c4e8 100644
--- a/patchwork/tests/test_rest_api.py
+++ b/patchwork/tests/test_rest_api.py
@@ -17,6 +17,7 @@
 # along with Patchwork; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
+import datetime
 import unittest
 
 from django.conf import settings
@@ -158,6 +159,29 @@ class TestPatchAPI(APITestCase):
         patch = resp.data['results'][0]
         self.assertEqual(patches[0].name, patch['name'])
 
+    def test_query_filters(self):
+        """Test out our filtering support."""
+        patches = create_patches(4)
+        project = Project.objects.create(
+            linkname='foo', name='Foo', listid='foo.example.com')
+        patches[0].project = project
+        patches[0].save()
+        resp = self.client.get('/api/1.0/patches/?project=Foo')
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(1, resp.data['count'])
+        self.assertEqual(patches[0].id, resp.data['results'][0]['id'])
+
+        ts = datetime.datetime.now().isoformat()
+        new_patches = create_patches(2)
+
+        resp = self.client.get('/api/1.0/patches/?until=%s' % ts)
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(len(patches), resp.data['count'])
+
+        resp = self.client.get('/api/1.0/patches/?since=%s' % ts)
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(len(new_patches), resp.data['count'])
+
     def test_get(self):
         """Validate we can get a specific project."""
         patches = create_patches()
diff --git a/patchwork/views/rest_api.py b/patchwork/views/rest_api.py
index 2e7fcbb..ae86627 100644
--- a/patchwork/views/rest_api.py
+++ b/patchwork/views/rest_api.py
@@ -63,8 +63,25 @@ class AuthenticatedReadOnly(permissions.BasePermission):
 class PatchworkViewSet(ModelViewSet):
     pagination_class = PageSizePagination
 
+    # a dict of the request-query-param -> django ORM query parameter
+    query_filters = {}
+
     def get_queryset(self):
-        return self.serializer_class.Meta.model.objects.all()
+        qs = self.serializer_class.Meta.model.objects.all()
+        filters = {}
+        for param, val in self.request.query_params.items():
+            name = self.query_filters.get(param)
+            if name:
+                filters[name] = val
+        return qs.filter(**filters)
+
+    def options(self, request, *args, **kwargs):
+        # add our query filters to make the "options" command a little more
+        # helpful.
+        resp = super(PatchworkViewSet, self).options(request, *args, **kwargs)
+        if self.query_filters:
+            resp.data['query_filters'] = self.query_filters.keys()
+        return resp
 
 
 def create_model_serializer(model_class, read_only=None):
@@ -76,11 +93,30 @@ def create_model_serializer(model_class, read_only=None):
 
 
 class PatchViewSet(PatchworkViewSet):
+    """Listings support the following query filters:
+        * project=<project-name>
+        * since=<YYYY-MM-DDTHH:MM:SS.mm>
+        * until=<YYYY-MM-DDTHH:MM:SS.mm>
+        * state=<state-name>
+        * submitter=<name>
+        * delegate=<name>
+
+       eg: GET /api/1.0/patches/?project=p&since=2016-01-01&submitter=User+Name
+    """
     permission_classes = (PatchworkPermission,)
     serializer_class = create_model_serializer(
         Patch, ('project', 'name', 'date', 'submitter', 'diff', 'content',
                 'hash', 'msgid'))
 
+    query_filters = {
+        'project': 'project__name',
+        'submitter': 'submitter__name',
+        'delegate': 'delegate__name',
+        'state': 'state__name',
+        'since': 'date__gt',
+        'until': 'date__lt',
+    }
+
 
 class PeopleViewSet(PatchworkViewSet):
     permission_classes = (AuthenticatedReadOnly,)
-- 
2.7.4



More information about the Patchwork mailing list