From patchwork Wed Apr 11 16:13:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897284 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lq0h34QVz9s27 for ; Thu, 12 Apr 2018 02:16:20 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="J+5pU2cN"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lq0h1QcCzF1RG for ; Thu, 12 Apr 2018 02:16:20 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="J+5pU2cN"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.214.30; helo=caracal.maple.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="J+5pU2cN"; dkim-atps=neutral Received: from caracal.maple.relay.mailchannels.net (caracal.maple.relay.mailchannels.net [23.83.214.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxw5LYdzF0dY for ; Thu, 12 Apr 2018 02:13:56 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id D94185C2F70 for ; Wed, 11 Apr 2018 16:13:48 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.14.60]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id E3D1C5C2B9A for ; Wed, 11 Apr 2018 16:13:46 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.55.125]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:47 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Reign-Gusty: 7666a68a17bc909b_1523463227492_1171292633 X-MC-Loop-Signature: 1523463227492:485189039 X-MC-Ingress-Time: 1523463227492 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=1gfuol8hOdObkK0jdT4qtwG/vevrvDflYf8F17RUJNI=; b=J+5pU2cNUAug1XyDKYaut0rktC JhEB/goh4VAqXMZEQwL8Va8t6NgIfHYogZhqegbXJwZ/mpLNAG1ObZLCCqdNn4x+HYNPG/+Lh9rA0 HKwfzm4NNlv1OSn43aETk1x3B7prrp07VnaPOlUPpUbhBG3/qQ+Ekmnw983BhRN9fcP8198yoU88b qQnJydgxwNvj7+3agPQwaDFNV2y2TwuHrsCGN+0s3NcBUIKRp/TJu/kHBEAOm6iidh2vKyfJB9CfQ w4Bg6SimxkdUi+FR3ZW3XO1Agr9V4pYUYQqwtk39GvFY4OrfzL9Almu74ryTcmoCyI3nzRTR6aSYA nxhAiQaQ==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 1/7] REST: Use UserFilter for patch delegates Date: Wed, 11 Apr 2018 17:13:32 +0100 Message-Id: <20180411161338.420-2-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Signed-off-by: Stephen Finucane --- patchwork/api/filters.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index eed7995d..25956e98 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -158,8 +158,9 @@ class CoverLetterFilter(ProjectMixin, TimestampMixin, FilterSet): class PatchFilter(ProjectMixin, TimestampMixin, FilterSet): - state = StateFilter(queryset=State.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) + delegate = UserFilter(queryset=User.objects.all()) + state = StateFilter(queryset=State.objects.all()) class Meta: model = Patch From patchwork Wed Apr 11 16:13:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897285 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lq1C2zhNz9s27 for ; Thu, 12 Apr 2018 02:16:47 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="SVRyJxdY"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lq1C1PSXzF1RP for ; Thu, 12 Apr 2018 02:16:47 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="SVRyJxdY"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.222.36; helo=cichlid.ash.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="SVRyJxdY"; dkim-atps=neutral Received: from cichlid.ash.relay.mailchannels.net (cichlid.ash.relay.mailchannels.net [23.83.222.36]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpy108lDzF1Qt for ; Thu, 12 Apr 2018 02:14:00 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 1144D5C3230 for ; Wed, 11 Apr 2018 16:13:48 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.15.83]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id D978C5C31F7 for ; Wed, 11 Apr 2018 16:13:46 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [100.96.15.1]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:48 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Industry-Occur: 7b1f99c34fd23035_1523463227617_2637374363 X-MC-Loop-Signature: 1523463227617:4164989518 X-MC-Ingress-Time: 1523463227617 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=mxawBTLyBD01OzWgfvyPiGMyalkmBxchzT++y/4JV+s=; b=SVRyJxdY6qr/A7x70NgjKmqKeC nDfey9bu8MeGG9wTIJOMDbiDx0TQQuJ+eK8v9MKPESiS6j2jyQXjRYLujCrz+xt6OtiNJJUxV49am jtjaTg6/tZdXnAF6Od08J/zDhbYrHkhix3owupTx7UAJmyoQs8E/xdLM+fLgU05MYwnacRED4jP8A bIBYRkg3xgBK15+tgoIdstThrjv7XklKP4peSDFMWFZe0iuewwwq7+6tEUKU3MNg0SxnYm7q8uLYv cpHwm3ZhBgUi+Ctlws9zZE1HRIDX6HHgBNMVEDCfi1ZIyAVfFuGlfF474QYhCHnCKBrP6IOCjq47C RXZlKXtg==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 2/7] REST: Simplify ModelMultiChoiceField Date: Wed, 11 Apr 2018 17:13:33 +0100 Message-Id: <20180411161338.420-3-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" We're actually going to remove this shortly but the new technique works for both. Signed-off-by: Stephen Finucane --- patchwork/api/filters.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 25956e98..030f9af3 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -46,7 +46,10 @@ class ModelMultiChoiceField(ModelChoiceField): if value in self.empty_values: return None - filters = self._get_filters(value) + try: + filters = {'pk': int(value)} + except ValueError: + filters = {self.alternate_lookup: value} try: value = self.queryset.get(**filters) @@ -58,11 +61,7 @@ class ModelMultiChoiceField(ModelChoiceField): class ProjectChoiceField(ModelMultiChoiceField): - def _get_filters(self, value): - try: - return {'pk': int(value)} - except ValueError: - return {'linkname__iexact': value} + alternate_lookup = 'linkname__iexact' class ProjectFilter(ModelChoiceFilter): @@ -72,11 +71,7 @@ class ProjectFilter(ModelChoiceFilter): class PersonChoiceField(ModelMultiChoiceField): - def _get_filters(self, value): - try: - return {'pk': int(value)} - except ValueError: - return {'email__iexact': value} + alternate_lookup = 'email__iexact' class PersonFilter(ModelChoiceFilter): @@ -111,11 +106,7 @@ class StateFilter(ModelChoiceFilter): class UserChoiceField(ModelMultiChoiceField): - def _get_filters(self, value): - try: - return {'pk': int(value)} - except ValueError: - return {'username__iexact': value} + alternate_lookup = 'username__iexact' class UserFilter(ModelChoiceFilter): From patchwork Wed Apr 11 16:13:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897273 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lpxy27FTz9s27 for ; Thu, 12 Apr 2018 02:13:58 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Xf9Q6Ogp"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lpxy0Y5QzF1RK for ; Thu, 12 Apr 2018 02:13:58 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Xf9Q6Ogp"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.214.32; helo=catfish.maple.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Xf9Q6Ogp"; dkim-atps=neutral Received: from catfish.maple.relay.mailchannels.net (catfish.maple.relay.mailchannels.net [23.83.214.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxs3cYrzF0dY for ; Thu, 12 Apr 2018 02:13:52 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 9A856282AB2 for ; Wed, 11 Apr 2018 16:13:47 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.13.37]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id DDEA42825ED for ; Wed, 11 Apr 2018 16:13:46 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [100.96.13.1]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:47 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Abaft-Towering: 4b8f329c35daea47_1523463227396_4231550284 X-MC-Loop-Signature: 1523463227396:1961171533 X-MC-Ingress-Time: 1523463227395 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=HhJtEl07qiNOkayegb/v8mevRpq8baVJOsULOHkRMT4=; b=Xf9Q6Ogp8pQ+B3q1hjtuKHff9p ShSeKwBThPDUjVi5emowE1c6AkmiBqTuRb8pm/iMfx4awVCinidEKofrTHWj2UhdR1u6PUAnhVCPA 8L2EK2GAJ5L5N9riwcwmSoGjFSxdGJQoMcwlV+1H3ySB3xvj5bBbj03QdczVH06VN7IN5ukGSviir 8poOlwWtDDq4oongtXNAos+YxxUCPzMQIe5VXmQ0Nq/f5iOrDMPTGMRIh7iV5nWuehx39S2c6zORx 7yG/vea7Xr6MFwtzsrU7RfJVpgNhA/8bL6A3X/Q15ZV72Wpyd6oIiS7oN1XPCIwrU0tUqN6XjxCjg J2IV6WRg==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 3/7] REST: Use ModelMultipleChoiceField Date: Wed, 11 Apr 2018 17:13:34 +0100 Message-Id: <20180411161338.420-4-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" We use a modified version of this that allows us to query on multiple fields. Signed-off-by: Stephen Finucane Fixes: #156 --- patchwork/api/filters.py | 103 ++++++++++++--------- patchwork/tests/api/test_patch.py | 15 ++- .../improved-rest-filtering-bf68399270a9b245.yaml | 10 +- 3 files changed, 82 insertions(+), 46 deletions(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 030f9af3..b30499d0 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -19,10 +19,11 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError +from django.db.models import Q from django_filters import FilterSet from django_filters import IsoDateTimeFilter -from django_filters import ModelChoiceFilter -from django.forms import ModelChoiceField +from django_filters import ModelMultipleChoiceFilter +from django.forms import ModelMultipleChoiceField as BaseMultipleChoiceField from patchwork.models import Bundle from patchwork.models import Check @@ -37,79 +38,96 @@ from patchwork.models import State # custom fields, filters -class ModelMultiChoiceField(ModelChoiceField): - - def _get_filters(self, value): - raise NotImplementedError - - def to_python(self, value): - if value in self.empty_values: - return None +class ModelMultipleChoiceField(BaseMultipleChoiceField): + def _get_filter(self, value): try: - filters = {'pk': int(value)} + return 'pk', int(value) except ValueError: - filters = {self.alternate_lookup: value} - + return self.alternate_lookup, value + + def _check_values(self, value): + """ + Given a list of possible PK values, returns a QuerySet of the + corresponding objects. Raises a ValidationError if a given value is + invalid (not a valid PK, not in the queryset, etc.) + """ + # deduplicate given values to avoid creating many querysets or + # requiring the database backend deduplicate efficiently. try: - value = self.queryset.get(**filters) - except (ValueError, TypeError, self.queryset.model.DoesNotExist): - raise ValidationError(self.error_messages['invalid_choice'], - code='invalid_choice') - return value + value = frozenset(value) + except TypeError: + # list of lists isn't hashable, for example + raise ValidationError( + self.error_messages['list'], + code='list', + ) + + q_objects = Q() + + for pk in value: + key, val = self._get_filter(pk) + + try: + # NOTE(stephenfin): In contrast to the Django implementation + # of this, we check to ensure each specified key exists and + # fail if not. If we don't this, we can end up doing nothing + # for the filtering which, to me, seems very confusing + self.queryset.get(**{key: val}) + except (ValueError, TypeError, self.queryset.model.DoesNotExist): + raise ValidationError( + self.error_messages['invalid_pk_value'], + code='invalid_pk_value', + params={'pk': val}, + ) + q_objects |= Q(**{key: val}) -class ProjectChoiceField(ModelMultiChoiceField): + qs = self.queryset.filter(q_objects) + + return qs + + +class ProjectChoiceField(ModelMultipleChoiceField): alternate_lookup = 'linkname__iexact' -class ProjectFilter(ModelChoiceFilter): +class ProjectFilter(ModelMultipleChoiceFilter): field_class = ProjectChoiceField -class PersonChoiceField(ModelMultiChoiceField): +class PersonChoiceField(ModelMultipleChoiceField): alternate_lookup = 'email__iexact' -class PersonFilter(ModelChoiceFilter): +class PersonFilter(ModelMultipleChoiceFilter): field_class = PersonChoiceField -class StateChoiceField(ModelChoiceField): +class StateChoiceField(ModelMultipleChoiceField): - def prepare_value(self, value): - if hasattr(value, '_meta'): - return value.slug - else: - return super(StateChoiceField, self).prepare_value(value) - - def to_python(self, value): - if value in self.empty_values: - return None + def _get_filter(self, value): try: - value = ' '.join(value.split('-')) - value = self.queryset.get(name__iexact=value) - except (ValueError, TypeError, self.queryset.model.DoesNotExist): - raise ValidationError(self.error_messages['invalid_choice'], - code='invalid_choice') - return value + return 'pk', int(value) + except ValueError: + return 'name__iexact', ' '.join(value.split('-')) -class StateFilter(ModelChoiceFilter): +class StateFilter(ModelMultipleChoiceFilter): field_class = StateChoiceField -class UserChoiceField(ModelMultiChoiceField): +class UserChoiceField(ModelMultipleChoiceField): alternate_lookup = 'username__iexact' -class UserFilter(ModelChoiceFilter): +class UserFilter(ModelMultipleChoiceFilter): field_class = UserChoiceField @@ -125,8 +143,7 @@ class TimestampMixin(FilterSet): class ProjectMixin(FilterSet): - project = ProjectFilter(to_field_name='linkname', - queryset=Project.objects.all()) + project = ProjectFilter(queryset=Project.objects.all()) class SeriesFilter(ProjectMixin, TimestampMixin, FilterSet): diff --git a/patchwork/tests/api/test_patch.py b/patchwork/tests/api/test_patch.py index 909c1eb4..373ee0d5 100644 --- a/patchwork/tests/api/test_patch.py +++ b/patchwork/tests/api/test_patch.py @@ -71,8 +71,8 @@ class TestPatchAPI(APITestCase): self.assertEqual(0, len(resp.data)) person_obj = create_person(email='test@example.com') - state_obj = create_state(name='Under Review') project_obj = create_project(linkname='myproject') + state_obj = create_state(name='Under Review') patch_obj = create_patch(state=state_obj, project=project_obj, submitter=person_obj) @@ -117,6 +117,19 @@ class TestPatchAPI(APITestCase): 'submitter': 'test@example.org'}) self.assertEqual(0, len(resp.data)) + state_obj_b = create_state(name='New') + create_patch(state=state_obj_b) + state_obj_c = create_state(name='RFC') + create_patch(state=state_obj_c) + + resp = self.client.get(self.api_url()) + self.assertEqual(3, len(resp.data)) + resp = self.client.get(self.api_url(), [('state', 'under-review')]) + self.assertEqual(1, len(resp.data)) + resp = self.client.get(self.api_url(), [('state', 'under-review'), + ('state', 'new')]) + self.assertEqual(2, len(resp.data)) + def test_detail(self): """Validate we can get a specific patch.""" patch = create_patch( diff --git a/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml b/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml index b1d12eb6..170e9621 100644 --- a/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml +++ b/releasenotes/notes/improved-rest-filtering-bf68399270a9b245.yaml @@ -8,9 +8,15 @@ api: $ curl /covers/?submitter=stephen@that.guru - | - Bundles can be filtered by owner and checks by user using username. For - example: + Bundles can be filtered by owner, patches by delegate and checks by user + using username. For example: .. code-block:: shell $ curl /bundles/?owner=stephenfin + - | + Filters can now be specified multiple times. For example: + + .. code-block:: shell + + $ curl /patches/?state=under-review&state=rfc From patchwork Wed Apr 11 16:13:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897275 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lpyx25kWz9s27 for ; Thu, 12 Apr 2018 02:14:49 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Sdf1f/zq"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lpyx0dQKzF1Rw for ; Thu, 12 Apr 2018 02:14:49 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Sdf1f/zq"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.209.66; helo=gecko.birch.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="Sdf1f/zq"; dkim-atps=neutral Received: from gecko.birch.relay.mailchannels.net (gecko.birch.relay.mailchannels.net [23.83.209.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxv5bsCzF0dY for ; Thu, 12 Apr 2018 02:13:55 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id B0C5F3E2695 for ; Wed, 11 Apr 2018 16:13:48 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.15.83]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id CCD583E3327 for ; Wed, 11 Apr 2018 16:13:47 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.55.125]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:48 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Harbor-Bored: 3e284549157a2478_1523463228207_1813906685 X-MC-Loop-Signature: 1523463228207:3170891671 X-MC-Ingress-Time: 1523463228207 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=sLAekzTXVHVGJIJ7qqMPyZz8bMsdKAsibVaHJF6T3RE=; b=Sdf1f/zqYOGCqC9Cr+P862ZiBA xoyjZPZiz70L5BVGibCybuWe0e+d+dnQM8Qwo6NfjfIXWOGqDa4/W66K/WC5J+GQQjsXpFjTfkvtk zedD7Zn20YsUKONyA434akHBKwEA8sDAMwv2OrQcSpii6i2A+drUisrLVlwYQHTgdfP/G4i9iAeLd QOdZ4C2EuCLT0QnaTQFLEhtHE1PR8Jg5yAAxpUwbo+Njdnivm3rmUkiU1SuZ8JXDIUUfMDeJDsUqW ZIm5dgPoDvMdAGYq0RZnTZATLA+NndCmj3s+6Ec27FHXpo2aBuIr7taE6ZHAXnyPhgoLA8AUhdZbv 6fa1h7PA==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 4/7] REST: Remove ProjectFilterMixin Date: Wed, 11 Apr 2018 17:13:35 +0100 Message-Id: <20180411161338.420-5-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Whatever benefits this was giving us in the past are no more and it simply confuses matters now. Signed-off-by: Stephen Finucane Reviewed-by: Daniel Axtens --- patchwork/api/filters.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index b30499d0..7d94d5ed 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -141,22 +141,19 @@ class TimestampMixin(FilterSet): since = IsoDateTimeFilter(name='date', lookup_expr='gte') -class ProjectMixin(FilterSet): - - project = ProjectFilter(queryset=Project.objects.all()) - - -class SeriesFilter(ProjectMixin, TimestampMixin, FilterSet): +class SeriesFilter(TimestampMixin, FilterSet): submitter = PersonFilter(queryset=Person.objects.all()) + project = ProjectFilter(queryset=Project.objects.all()) class Meta: model = Series fields = ('submitter', 'project') -class CoverLetterFilter(ProjectMixin, TimestampMixin, FilterSet): +class CoverLetterFilter(TimestampMixin, FilterSet): + project = ProjectFilter(queryset=Project.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) class Meta: @@ -164,8 +161,9 @@ class CoverLetterFilter(ProjectMixin, TimestampMixin, FilterSet): fields = ('project', 'series', 'submitter') -class PatchFilter(ProjectMixin, TimestampMixin, FilterSet): +class PatchFilter(TimestampMixin, FilterSet): + project = ProjectFilter(queryset=Project.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) delegate = UserFilter(queryset=User.objects.all()) state = StateFilter(queryset=State.objects.all()) @@ -185,15 +183,18 @@ class CheckFilter(TimestampMixin, FilterSet): fields = ('user', 'state', 'context') -class EventFilter(ProjectMixin, TimestampMixin, FilterSet): +class EventFilter(TimestampMixin, FilterSet): + + project = ProjectFilter(queryset=Project.objects.all()) class Meta: model = Event fields = ('project', 'category', 'series', 'patch', 'cover') -class BundleFilter(ProjectMixin, FilterSet): +class BundleFilter(FilterSet): + project = ProjectFilter(queryset=Project.objects.all()) owner = UserFilter(queryset=User.objects.all()) class Meta: From patchwork Wed Apr 11 16:13:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897276 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40LpzK3y5dz9s27 for ; Thu, 12 Apr 2018 02:15:09 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="ZkNprdDK"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40LpzK2QfBzF1RP for ; Thu, 12 Apr 2018 02:15:09 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="ZkNprdDK"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.214.32; helo=catfish.maple.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="ZkNprdDK"; dkim-atps=neutral Received: from catfish.maple.relay.mailchannels.net (catfish.maple.relay.mailchannels.net [23.83.214.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxw1tMgzF0sk for ; Thu, 12 Apr 2018 02:13:55 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 309501232BE for ; Wed, 11 Apr 2018 16:13:50 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.33.32]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id 691D012323D for ; Wed, 11 Apr 2018 16:13:49 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.63.202]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:50 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Lyrical-Zesty: 3b0fe7d0798f0167_1523463229716_959753229 X-MC-Loop-Signature: 1523463229716:982495712 X-MC-Ingress-Time: 1523463229716 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=pM8JYlWzvOT/Wq+txtN2O5aq3pFRF4Y2bRsrQ8NZquw=; b=ZkNprdDKjRkup5rg1+Njrusz5o 8uS5vM+vbDa3XJI/RG7+5bYaC+D8/JNX2AFRZEIC7MHqQIv+C1RuwBNjZRUYgE77IbiWVeyKEMJ/u CdmfAJpkGEX2/WmVQA1IxL6STWrfHJCDdMuOXfQvRAmPWZqBQMA506ph3SwJ11H4IjgotZQeTXtLf G8uMw09IAKRbe8yP8ji7imCsLpdZ9B8ujn9Lr90ZTx8s2VI1wZpP3QNMAxRl8IxD29clJr7ztD7mV k3aqfuy335WabJos9/cG+DmY/5cm/QOi6ZVBTRErc0ez0+WWaxL+7uxFzalJlwREC83IjuhI3mbej oCMivguQ==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 5/7] REST: Rename Filter -> FilterSet Date: Wed, 11 Apr 2018 17:13:36 +0100 Message-Id: <20180411161338.420-6-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" This was confusing and will conflict with some forthcoming changes. Signed-off-by: Stephen Finucane --- patchwork/api/bundle.py | 4 ++-- patchwork/api/check.py | 4 ++-- patchwork/api/cover.py | 4 ++-- patchwork/api/event.py | 4 ++-- patchwork/api/filters.py | 12 ++++++------ patchwork/api/patch.py | 4 ++-- patchwork/api/series.py | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/patchwork/api/bundle.py b/patchwork/api/bundle.py index 0278592a..733e4881 100644 --- a/patchwork/api/bundle.py +++ b/patchwork/api/bundle.py @@ -24,7 +24,7 @@ from rest_framework.serializers import HyperlinkedModelSerializer from rest_framework.serializers import SerializerMethodField from patchwork.api.base import PatchworkPermission -from patchwork.api.filters import BundleFilter +from patchwork.api.filters import BundleFilterSet from patchwork.api.embedded import PatchSerializer from patchwork.api.embedded import ProjectSerializer from patchwork.api.embedded import UserSerializer @@ -73,7 +73,7 @@ class BundleMixin(object): class BundleList(BundleMixin, ListAPIView): """List bundles.""" - filter_class = BundleFilter + filter_class = BundleFilterSet search_fields = ('name',) ordering_fields = ('id', 'name', 'owner') ordering = 'id' diff --git a/patchwork/api/check.py b/patchwork/api/check.py index b37d6e01..8753c7de 100644 --- a/patchwork/api/check.py +++ b/patchwork/api/check.py @@ -27,7 +27,7 @@ from rest_framework.serializers import HyperlinkedModelSerializer from patchwork.api.base import CheckHyperlinkedIdentityField from patchwork.api.base import MultipleFieldLookupMixin from patchwork.api.embedded import UserSerializer -from patchwork.api.filters import CheckFilter +from patchwork.api.filters import CheckFilterSet from patchwork.models import Check from patchwork.models import Patch @@ -80,7 +80,7 @@ class CheckSerializer(HyperlinkedModelSerializer): class CheckMixin(object): serializer_class = CheckSerializer - filter_class = CheckFilter + filter_class = CheckFilterSet def get_queryset(self): return Check.objects.prefetch_related('patch', 'user') diff --git a/patchwork/api/cover.py b/patchwork/api/cover.py index fc7ae97b..9c9dc738 100644 --- a/patchwork/api/cover.py +++ b/patchwork/api/cover.py @@ -24,7 +24,7 @@ from rest_framework.generics import RetrieveAPIView from rest_framework.serializers import SerializerMethodField from patchwork.api.base import BaseHyperlinkedModelSerializer -from patchwork.api.filters import CoverLetterFilter +from patchwork.api.filters import CoverLetterFilterSet from patchwork.api.embedded import PersonSerializer from patchwork.api.embedded import ProjectSerializer from patchwork.api.embedded import SeriesSerializer @@ -74,7 +74,7 @@ class CoverLetterList(ListAPIView): """List cover letters.""" serializer_class = CoverLetterListSerializer - filter_class = CoverLetterFilter + filter_class = CoverLetterFilterSet search_fields = ('name',) ordering_fields = ('id', 'name', 'date', 'submitter') ordering = 'id' diff --git a/patchwork/api/event.py b/patchwork/api/event.py index 9879a9f6..b6626ec7 100644 --- a/patchwork/api/event.py +++ b/patchwork/api/event.py @@ -32,7 +32,7 @@ from patchwork.api.embedded import PatchSerializer from patchwork.api.embedded import ProjectSerializer from patchwork.api.embedded import SeriesSerializer from patchwork.api.embedded import UserSerializer -from patchwork.api.filters import EventFilter +from patchwork.api.filters import EventFilterSet from patchwork.api.patch import StateField from patchwork.models import Event @@ -104,7 +104,7 @@ class EventList(ListAPIView): renderer_classes = (JSONRenderer, JSONListHTMLRenderer) template_name = 'patchwork/event-list.html' serializer_class = EventSerializer - filter_class = EventFilter + filter_class = EventFilterSet page_size_query_param = None # fixed page size ordering_fields = () ordering = '-date' diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 7d94d5ed..afef10f4 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -141,7 +141,7 @@ class TimestampMixin(FilterSet): since = IsoDateTimeFilter(name='date', lookup_expr='gte') -class SeriesFilter(TimestampMixin, FilterSet): +class SeriesFilterSet(TimestampMixin, FilterSet): submitter = PersonFilter(queryset=Person.objects.all()) project = ProjectFilter(queryset=Project.objects.all()) @@ -151,7 +151,7 @@ class SeriesFilter(TimestampMixin, FilterSet): fields = ('submitter', 'project') -class CoverLetterFilter(TimestampMixin, FilterSet): +class CoverLetterFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) @@ -161,7 +161,7 @@ class CoverLetterFilter(TimestampMixin, FilterSet): fields = ('project', 'series', 'submitter') -class PatchFilter(TimestampMixin, FilterSet): +class PatchFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) @@ -174,7 +174,7 @@ class PatchFilter(TimestampMixin, FilterSet): 'state', 'archived') -class CheckFilter(TimestampMixin, FilterSet): +class CheckFilterSet(TimestampMixin, FilterSet): user = UserFilter(queryset=User.objects.all()) @@ -183,7 +183,7 @@ class CheckFilter(TimestampMixin, FilterSet): fields = ('user', 'state', 'context') -class EventFilter(TimestampMixin, FilterSet): +class EventFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) @@ -192,7 +192,7 @@ class EventFilter(TimestampMixin, FilterSet): fields = ('project', 'category', 'series', 'patch', 'cover') -class BundleFilter(FilterSet): +class BundleFilterSet(FilterSet): project = ProjectFilter(queryset=Project.objects.all()) owner = UserFilter(queryset=User.objects.all()) diff --git a/patchwork/api/patch.py b/patchwork/api/patch.py index 115feffa..eee3818e 100644 --- a/patchwork/api/patch.py +++ b/patchwork/api/patch.py @@ -28,7 +28,7 @@ from rest_framework.serializers import HyperlinkedModelSerializer from rest_framework.serializers import SerializerMethodField from patchwork.api.base import PatchworkPermission -from patchwork.api.filters import PatchFilter +from patchwork.api.filters import PatchFilterSet from patchwork.api.embedded import PersonSerializer from patchwork.api.embedded import ProjectSerializer from patchwork.api.embedded import SeriesSerializer @@ -143,7 +143,7 @@ class PatchList(ListAPIView): permission_classes = (PatchworkPermission,) serializer_class = PatchListSerializer - filter_class = PatchFilter + filter_class = PatchFilterSet search_fields = ('name',) ordering_fields = ('id', 'name', 'project', 'date', 'state', 'archived', 'submitter', 'check') diff --git a/patchwork/api/series.py b/patchwork/api/series.py index b5f4450a..ab1b6adb 100644 --- a/patchwork/api/series.py +++ b/patchwork/api/series.py @@ -23,7 +23,7 @@ from rest_framework.serializers import HyperlinkedModelSerializer from rest_framework.serializers import SerializerMethodField from patchwork.api.base import PatchworkPermission -from patchwork.api.filters import SeriesFilter +from patchwork.api.filters import SeriesFilterSet from patchwork.api.embedded import CoverLetterSerializer from patchwork.api.embedded import PatchSerializer from patchwork.api.embedded import PersonSerializer @@ -68,7 +68,7 @@ class SeriesMixin(object): class SeriesList(SeriesMixin, ListAPIView): """List series.""" - filter_class = SeriesFilter + filter_class = SeriesFilterSet search_fields = ('name',) ordering_fields = ('id', 'name', 'date', 'submitter', 'received_all') ordering = 'id' From patchwork Wed Apr 11 16:13:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897282 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lpzp1svHz9s27 for ; Thu, 12 Apr 2018 02:15:34 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="CtnxlJoM"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lpzn5bVCzF1R7 for ; Thu, 12 Apr 2018 02:15:33 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="CtnxlJoM"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.209.75; helo=gorilla.birch.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="CtnxlJoM"; dkim-atps=neutral Received: from gorilla.birch.relay.mailchannels.net (gorilla.birch.relay.mailchannels.net [23.83.209.75]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxw4V6JzF1Qt for ; Thu, 12 Apr 2018 02:13:56 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 7EC4212320C for ; Wed, 11 Apr 2018 16:13:50 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.11.60]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id 9D682122840 for ; Wed, 11 Apr 2018 16:13:49 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.52.53]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:50 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Abortive-Towering: 58bb6d190e25788b_1523463229920_654246644 X-MC-Loop-Signature: 1523463229920:196684425 X-MC-Ingress-Time: 1523463229920 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=cc1fRYMtfpdnQPbWkVWyffm3PX30xlsJhGZa7gbexhE=; b=CtnxlJoMyBcPPZkaZ3HwSalB2K gK3PZxVm0eh2W54pwzOu5WGJjMJ5XqJT1qqbzHVZ2aBgcmQ4AUTSkHYwDTfEqLB57y5mFCNjyLxaC wk8bM396xu5axxf2GFGB6ysEtpiaw7P2QlbOZv1NitALDIwEzpa294R+tkkw7XF6xzUlNm/URmFjW nUPOUxq7u7i0f/tEH4BkJzEUnQvuFk8/s+k3c3mNtY6hWUEN21E0Y3fPCmhx4WHeKYGN0HIVgkFN4 Sr5521+cf2C1Es4W0hqQCHGsJtodHAKEAXCWSAJZ0leUtFI/mUzgUcy7u1AnwUxCVuCHO+ih5jCax apAoZxOQ==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 6/7] REST: Use ModelMultipleChoiceField for other fields Date: Wed, 11 Apr 2018 17:13:37 +0100 Message-Id: <20180411161338.420-7-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" There's benefit to being able to do stuff like select multiple patches. Let's do that. Signed-off-by: Stephen Finucane --- patchwork/api/filters.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index afef10f4..4d8d504d 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -41,6 +41,9 @@ from patchwork.models import State class ModelMultipleChoiceField(BaseMultipleChoiceField): def _get_filter(self, value): + if not self.alternate_lookup: + return 'pk', value + try: return 'pk', int(value) except ValueError: @@ -88,14 +91,14 @@ class ModelMultipleChoiceField(BaseMultipleChoiceField): return qs -class ProjectChoiceField(ModelMultipleChoiceField): +class BaseField(ModelMultipleChoiceField): - alternate_lookup = 'linkname__iexact' + alternate_lookup = None -class ProjectFilter(ModelMultipleChoiceFilter): +class BaseFilter(ModelMultipleChoiceFilter): - field_class = ProjectChoiceField + field_class = BaseField class PersonChoiceField(ModelMultipleChoiceField): @@ -108,6 +111,16 @@ class PersonFilter(ModelMultipleChoiceFilter): field_class = PersonChoiceField +class ProjectChoiceField(ModelMultipleChoiceField): + + alternate_lookup = 'linkname__iexact' + + +class ProjectFilter(ModelMultipleChoiceFilter): + + field_class = ProjectChoiceField + + class StateChoiceField(ModelMultipleChoiceField): def _get_filter(self, value): @@ -154,6 +167,7 @@ class SeriesFilterSet(TimestampMixin, FilterSet): class CoverLetterFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) + series = BaseFilter(queryset=Project.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) class Meta: @@ -164,6 +178,7 @@ class CoverLetterFilterSet(TimestampMixin, FilterSet): class PatchFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) + series = BaseFilter(queryset=Series.objects.all()) submitter = PersonFilter(queryset=Person.objects.all()) delegate = UserFilter(queryset=User.objects.all()) state = StateFilter(queryset=State.objects.all()) @@ -186,6 +201,9 @@ class CheckFilterSet(TimestampMixin, FilterSet): class EventFilterSet(TimestampMixin, FilterSet): project = ProjectFilter(queryset=Project.objects.all()) + series = BaseFilter(queryset=Series.objects.all()) + patch = BaseFilter(queryset=Patch.objects.all()) + cover = BaseFilter(queryset=CoverLetter.objects.all()) class Meta: model = Event From patchwork Wed Apr 11 16:13:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 897283 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40Lq0G3x4Xz9s27 for ; Thu, 12 Apr 2018 02:15:58 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="gWIg57zF"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40Lq0F4RjvzF1RZ for ; Thu, 12 Apr 2018 02:15:57 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="gWIg57zF"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.209.75; helo=gorilla.birch.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="gWIg57zF"; dkim-atps=neutral Received: from gorilla.birch.relay.mailchannels.net (gorilla.birch.relay.mailchannels.net [23.83.209.75]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40Lpxw4yptzF1Qy for ; Thu, 12 Apr 2018 02:13:56 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 56C001231A4 for ; Wed, 11 Apr 2018 16:13:51 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.14.60]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id 48B2412329A for ; Wed, 11 Apr 2018 16:13:50 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.49.137]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Wed, 11 Apr 2018 16:13:51 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Wide-Eyed-Bottle: 6a4d914143b0fff1_1523463230577_480843155 X-MC-Loop-Signature: 1523463230577:2662458396 X-MC-Ingress-Time: 1523463230576 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=xyHOhJ1fyQnSBQWvxvoxw7gAs1uT6eCINFQ0T88wKH0=; b=gWIg57zFrzdxEXXI4JuxMIzV8c zQyWRnjw+Fw/YJg/b7A98Kan27esRF9WBdvQqfvL6r92k0C7bq8LNhOWf3Vz0L90mKD7fOGQnINW+ M8akFHUY4X0BBywYgzYaVubMr8yn1r4vCnreOpRZYkefqVveDlfAXTfxnL6oqIpM6i5hoggS6u7ZO Kih78bK8gW8kmhNAl1qjF5qfOk6suGLZyiczrEGwy/QiTLTuuq2aaEHUk8PCrHwUOsjrsnkm+mxg6 j+ckcpnr5r4/xYEoR9zlbB6TEciVoOZZRTjlMBwj2sR3h42I/G3UCigQKNDQRSJvOGYc3pru8POgh FduA6GPg==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 7/7] REST: Use DRF-specific filterset Date: Wed, 11 Apr 2018 17:13:38 +0100 Message-Id: <20180411161338.420-8-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180411161338.420-1-stephen@that.guru> References: <20180411161338.420-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Better error handling, yo. Signed-off-by: Stephen Finucane --- patchwork/api/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 4d8d504d..f6fff792 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -20,7 +20,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db.models import Q -from django_filters import FilterSet +from django_filters.rest_framework import FilterSet from django_filters import IsoDateTimeFilter from django_filters import ModelMultipleChoiceFilter from django.forms import ModelMultipleChoiceField as BaseMultipleChoiceField