Issue
Using django-filters, I see various solutions for how to submit multiple arguments of the same type in a single query string, for example for multiple IDs. They all suggest using a separate field that contains a comma-separated list of values, e.g.:
http://example.com/api/cities?ids=1,2,3
Is there a general solution for using a single parameter but submitted one or more times? E.g.:
http://example.com/api/cities?id=1&id=2&id=3
I tried using MultipleChoiceFilter
, but it expects actual choices to be defined whereas I want to pass arbitrary IDs (some of which may not even exist in the DB).
Solution
Here is a reusable solution using a custom Filter
and a custom Field
.
The custom Field
reuses Django's MultipleChoiceField but replaces the validation functions.
Instead, it validates using another Field
class that we pass to the constructor.
from django.forms.fields import MultipleChoiceField
class MultipleValueField(MultipleChoiceField):
def __init__(self, *args, field_class, **kwargs):
self.inner_field = field_class()
super().__init__(*args, **kwargs)
def valid_value(self, value):
return self.inner_field.validate(value)
def clean(self, values):
return values and [self.inner_field.clean(value) for value in values]
The custom Filter
uses MultipleValueField
and forwards the field_class
argument.
It also sets the default value of lookup_expr
to in
.
from django_filters.filters import Filter
class MultipleValueFilter(Filter):
field_class = MultipleValueField
def __init__(self, *args, field_class, **kwargs):
kwargs.setdefault('lookup_expr', 'in')
super().__init__(*args, field_class=field_class, **kwargs)
To use this filter, simply create a MultipleValueFilter
with the appropriate field_class
. For example, to filter City
by id
, we can use a IntegerField, like so:
from django.forms.fields import IntegerField
class CityFilterSet(FilterSet):
id = MultipleValueFilter(field_class=IntegerField)
name = filters.CharFilter(lookup_expr='icontains')
class Meta:
model = City
fields = ['name']
Answered By - Benoit Blanchon
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.