diff mbox

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

Message ID 1462919967-26088-10-git-send-email-andy.doan@linaro.org
State Superseded
Headers show

Commit Message

Andy Doan May 10, 2016, 10:39 p.m. UTC
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@linaro.org>
---
 patchwork/tests/test_rest_api.py | 26 +++++++++++++++++++++++++-
 patchwork/views/rest_api.py      | 38 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 62 insertions(+), 2 deletions(-)

Comments

Stephen Finucane May 17, 2016, 1:43 p.m. UTC | #1
On 10 May 17:39, Andy Doan wrote:
> 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@linaro.org>

Not reviewing yet, pending comments on v1.

Stephen
Andy Doan May 19, 2016, 3:25 a.m. UTC | #2
On 05/17/2016 08:43 AM, Finucane, Stephen wrote:
> On 10 May 17:39, Andy Doan wrote:
>> 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@linaro.org>
>
> Not reviewing yet, pending comments on v1.

I'm going to drop this from this series and address in a follow-up patch 
to help make this a little easier.
diff mbox

Patch

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,)