Skip to content

Commit 28728fd

Browse files
committed
Merge pull request #36 from karmux/master
__in filter works with strings.
2 parents 8e83ad1 + 4305876 commit 28728fd

File tree

4 files changed

+75
-10
lines changed

4 files changed

+75
-10
lines changed

rest_framework_filters/fields.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,14 @@ def clean(self, value):
1515
for val in value.split(','):
1616
out.append(super(ArrayDecimalField, self).clean(val))
1717
return out
18+
19+
20+
class ArrayCharField(forms.CharField):
21+
def clean(self, value):
22+
if value is None:
23+
return None
24+
25+
out = []
26+
for val in value.split(','):
27+
out.append(super(ArrayCharField, self).clean(val))
28+
return out

rest_framework_filters/filters.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ class TimeFilter(TimeFilter):
3939
field_class = fields.Django14TimeField
4040

4141

42-
class InSetNumberFilter(NumberFilter):
43-
field_class = fields.ArrayDecimalField
44-
42+
class InSetFilterBase(object):
4543
def filter(self, qs, value):
4644
if value in ([], (), {}, None, ''):
4745
return qs
@@ -50,3 +48,11 @@ def filter(self, qs, value):
5048
if self.distinct:
5149
qs = qs.distinct()
5250
return qs
51+
52+
53+
class InSetNumberFilter(InSetFilterBase, NumberFilter):
54+
field_class = fields.ArrayDecimalField
55+
56+
57+
class InSetCharFilter(InSetFilterBase, NumberFilter):
58+
field_class = fields.ArrayCharField

rest_framework_filters/filterset.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ def fix_filter_field(self, f):
7474
lookup_type = f.lookup_type
7575
if lookup_type == 'isnull':
7676
return filters.BooleanFilter(name=("%s%sisnull" % (f.name, LOOKUP_SEP)))
77-
if lookup_type == 'in' and type(f) in [filters.NumberFilter]:
77+
if lookup_type == 'in' and type(f) == filters.NumberFilter:
7878
return filters.InSetNumberFilter(name=("%s%sin" % (f.name, LOOKUP_SEP)))
79+
if lookup_type == 'in' and type(f) == filters.CharFilter:
80+
return filters.InSetCharFilter(name=("%s%sin" % (f.name, LOOKUP_SEP)))
7981
return f
8082

8183
def populate_from_filterset(self, filterset, filter_, name):

rest_framework_filters/tests.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,21 @@ class ExplicitLookupsPersonDateFilter(FilterSet):
238238
class Meta:
239239
model = Person
240240

241-
class InSetLookupPersonFilter(FilterSet):
241+
242+
class InSetLookupPersonIDFilter(FilterSet):
242243
pk = AllLookupsFilter('id')
243244

244245
class Meta:
245246
model = Person
246247

248+
249+
class InSetLookupPersonNameFilter(FilterSet):
250+
name = AllLookupsFilter('name')
251+
252+
class Meta:
253+
model = Person
254+
255+
247256
class TestFilterSets(TestCase):
248257

249258
if django.VERSION >= (1, 8):
@@ -679,14 +688,14 @@ class Meta:
679688
p = list(f)[0]
680689
self.assertEqual(p.name, "John")
681690

682-
def test_inset_filter(self):
691+
def test_inset_number_filter(self):
683692
p1 = Person.objects.get(name="John").pk
684693
p2 = Person.objects.get(name="Mark").pk
685694

686695
ALL_GET = {
687696
'pk__in': '{:d},{:d}'.format(p1, p2),
688697
}
689-
f = InSetLookupPersonFilter(ALL_GET, queryset=Person.objects.all())
698+
f = InSetLookupPersonIDFilter(ALL_GET, queryset=Person.objects.all())
690699
f = [x.pk for x in f]
691700
self.assertEqual(len(f), 2)
692701
self.assertIn(p1, f)
@@ -696,13 +705,13 @@ def test_inset_filter(self):
696705
INVALID_GET = {
697706
'pk__in': '{:d},c{:d}'.format(p1, p2)
698707
}
699-
f = InSetLookupPersonFilter(INVALID_GET, queryset=Person.objects.all())
708+
f = InSetLookupPersonIDFilter(INVALID_GET, queryset=Person.objects.all())
700709
self.assertEqual(len(list(f)), 0)
701710

702711
EXTRA_GET = {
703712
'pk__in': '{:d},{:d},{:d}'.format(p1, p2, p1*p2)
704713
}
705-
f = InSetLookupPersonFilter(EXTRA_GET, queryset=Person.objects.all())
714+
f = InSetLookupPersonIDFilter(EXTRA_GET, queryset=Person.objects.all())
706715
f = [x.pk for x in f]
707716
self.assertEqual(len(f), 2)
708717
self.assertIn(p1, f)
@@ -711,8 +720,45 @@ def test_inset_filter(self):
711720
DISORDERED_GET = {
712721
'pk__in': '{:d},{:d},{:d}'.format(p2, p2*p1, p1)
713722
}
714-
f = InSetLookupPersonFilter(DISORDERED_GET, queryset=Person.objects.all())
723+
f = InSetLookupPersonIDFilter(DISORDERED_GET, queryset=Person.objects.all())
715724
f = [x.pk for x in f]
716725
self.assertEqual(len(f), 2)
717726
self.assertIn(p1, f)
718727
self.assertIn(p2, f)
728+
729+
def test_inset_char_filter(self):
730+
p1 = Person.objects.get(name="John").name
731+
p2 = Person.objects.get(name="Mark").name
732+
733+
ALL_GET = {
734+
'name__in': '{},{}'.format(p1, p2),
735+
}
736+
f = InSetLookupPersonNameFilter(ALL_GET, queryset=Person.objects.all())
737+
f = [x.name for x in f]
738+
self.assertEqual(len(f), 2)
739+
self.assertIn(p1, f)
740+
self.assertIn(p2, f)
741+
742+
NONEXISTENT_GET = {
743+
'name__in': '{},Foo{}'.format(p1, p2)
744+
}
745+
f = InSetLookupPersonNameFilter(NONEXISTENT_GET, queryset=Person.objects.all())
746+
self.assertEqual(len(list(f)), 1)
747+
748+
EXTRA_GET = {
749+
'name__in': '{},{},{}'.format(p1, p2, p1+p2)
750+
}
751+
f = InSetLookupPersonNameFilter(EXTRA_GET, queryset=Person.objects.all())
752+
f = [x.name for x in f]
753+
self.assertEqual(len(f), 2)
754+
self.assertIn(p1, f)
755+
self.assertIn(p2, f)
756+
757+
DISORDERED_GET = {
758+
'name__in': '{},{},{}'.format(p2, p2+p1, p1)
759+
}
760+
f = InSetLookupPersonNameFilter(DISORDERED_GET, queryset=Person.objects.all())
761+
f = [x.name for x in f]
762+
self.assertEqual(len(f), 2)
763+
self.assertIn(p1, f)
764+
self.assertIn(p2, f)

0 commit comments

Comments
 (0)