From a5239bfba9a3d30eb7ce7467b824cfee2fe1cfa1 Mon Sep 17 00:00:00 2001 From: Konrad Mohrfeldt <konrad.mohrfeldt@farbdev.org> Date: Mon, 28 Mar 2022 23:57:22 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20don=E2=80=99t=20enforce=20valid=20instan?= =?UTF-8?q?ce=20references=20in=20collection=20filters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a collection is filtered by an invalid id (meaning the model the query argument points to with that specific id does not exist), we no longer return an error. Instead the filter is applied without a lookup. Fixes #104 --- program/filters.py | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/program/filters.py b/program/filters.py index ea43ff7b..8478b6f9 100644 --- a/program/filters.py +++ b/program/filters.py @@ -3,7 +3,7 @@ import datetime from django_filters import rest_framework as filters from django_filters import widgets -from django.contrib.auth.models import User +from django import forms from django.db.models import Q, QuerySet from django.utils import timezone from program import models @@ -19,7 +19,7 @@ class StaticFilterHelpTextMixin: return _filter -class ModelMultipleChoiceFilter(filters.ModelMultipleChoiceFilter): +class IntegerInFilter(filters.BaseInFilter): class QueryArrayWidget(widgets.QueryArrayWidget): # see: https://github.com/carltongibson/django-filter/issues/1047 def value_from_datadict(self, data, files, name): @@ -31,17 +31,12 @@ class ModelMultipleChoiceFilter(filters.ModelMultipleChoiceFilter): new_data[key] = data.getlist(key) return super().value_from_datadict(new_data, files, name) + field_class = forms.IntegerField + def __init__(self, *args, **kwargs): kwargs.setdefault("widget", self.QueryArrayWidget()) - kwargs["lookup_expr"] = "in" super().__init__(*args, **kwargs) - def get_filter_predicate(self, v): - # There is something wrong with using ModelMultipleChoiceFilter - # along the CSVWidget that causes lookups to fail. - # May be related to: https://github.com/carltongibson/django-filter/issues/1103 - return super().get_filter_predicate([v.pk]) - class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): active = filters.BooleanFilter( @@ -52,34 +47,31 @@ class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): "or past or upcoming shows if false." ), ) - host = ModelMultipleChoiceFilter( - queryset=models.Host.objects.all(), + host = IntegerInFilter( field_name="hosts", help_text="Return only shows assigned to the given host(s).", ) # TODO: replace `musicfocus` with `music_focus` when dashboard is updated - musicfocus = ModelMultipleChoiceFilter( - queryset=models.MusicFocus.objects.all(), + musicfocus = IntegerInFilter( field_name="music_focus", help_text="Return only shows with given music focus(es).", ) - owner = ModelMultipleChoiceFilter( - queryset=User.objects.all(), + owner = IntegerInFilter( field_name="owners", help_text="Return only shows that belong to the given owner(s).", ) - category = ModelMultipleChoiceFilter( - queryset=models.Category.objects.all(), + category = IntegerInFilter( help_text="Return only shows of the given category or categories.", ) - language = ModelMultipleChoiceFilter( - queryset=models.Language.objects.all(), + language = IntegerInFilter( help_text="Return only shows of the given language(s).", ) - topic = ModelMultipleChoiceFilter( - queryset=models.Topic.objects.all(), + topic = IntegerInFilter( help_text="Return only shows of the given topic(s).", ) + type = IntegerInFilter( + help_text="Return only shows of a given type.", + ) public = filters.BooleanFilter( field_name="is_public", help_text="Return only shows that are public/non-public.", @@ -113,9 +105,6 @@ class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): class Meta: model = models.Show - help_texts = { - "type": "Return only shows of a given type.", - } fields = [ "active", "category", @@ -224,14 +213,12 @@ class TimeSlotFilterSet(filters.FilterSet): class NoteFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): - ids = ModelMultipleChoiceFilter( + ids = IntegerInFilter( field_name="id", - queryset=models.Note.objects.all(), help_text="Return only notes matching the specified id(s).", ) - owner = ModelMultipleChoiceFilter( + owner = IntegerInFilter( field_name="show__owners", - queryset=models.User.objects.all(), help_text="Return only notes by show the specified owner(s): all notes the user may edit.", ) -- GitLab