[PATCHv2 09/10] REST: Add query parameters to filter patches by

Andy Doan andy.doan at linaro.org
Wed May 11 08:39:26 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 | 26 +++++++++++++++++++++++++-
 patchwork/views/rest_api.py      | 38 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/patchwork/tests/test_rest_api.py b/patchwork/tests/test_rest_api.py
index 2bf8f94..6f1a375 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
@@ -161,7 +162,7 @@ class TestPersonAPI(APITestCase):
 class TestPatchAPI(APITestCase):
     fixtures = ['default_states']
 
-    def api_url(self, item=None):
+    def api_url(self, item=None, query=None):
         if item is None:
             return reverse('api_1.0:patch-list')
         return reverse('api_1.0:patch-detail', args=[item])
@@ -184,6 +185,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(self.api_url() + '?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(self.api_url() + '?until=%s' % ts)
+        self.assertEqual(status.HTTP_200_OK, resp.status_code)
+        self.assertEqual(len(patches), resp.data['count'])
+
+        resp = self.client.get(self.api_url() + '?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 4bfec68..e5a642a 100644
--- a/patchwork/views/rest_api.py
+++ b/patchwork/views/rest_api.py
@@ -59,14 +59,50 @@ 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
 
 
 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 = PatchSerializer
 
+    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