Skip to content

Commit 758dfd4

Browse files
committed
provides support for query array notation
1 parent da3ed3b commit 758dfd4

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

django_filters/widgets.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from django import forms
1212
from django.db.models.fields import BLANK_CHOICE_DASH
1313
from django.forms.widgets import flatatt
14+
from django.utils.datastructures import MultiValueDict
1415
from django.utils.encoding import force_text
1516
from django.utils.safestring import mark_safe
1617
from django.utils.six import string_types
@@ -171,3 +172,29 @@ def render(self, name, value, attrs=None):
171172

172173
class CSVWidget(BaseCSVWidget, forms.TextInput):
173174
pass
175+
176+
177+
class QueryArrayWidget(BaseCSVWidget, forms.TextInput):
178+
"""
179+
Enables request query array notation that might be consumed by MultipleChoiceFilter
180+
181+
1. Values can be provided as csv string: ?foo=bar,baz
182+
2. Values can be provided as query array: ?foo[]=bar&foo[]=baz
183+
"""
184+
185+
def value_from_datadict(self, data, files, name):
186+
if not isinstance(data, MultiValueDict):
187+
data = MultiValueDict(data)
188+
189+
request_data = data.getlist(name, data.getlist('%s[]' % name))
190+
if isinstance(request_data, string_types):
191+
request_data = [request_data]
192+
193+
if not request_data:
194+
return []
195+
196+
extracted_data = set()
197+
for item in request_data:
198+
extracted_data.update([x.strip() for x in item.rstrip(',').split(',') if x])
199+
200+
return list(extracted_data)

tests/test_widgets.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.test import TestCase
55
from django.forms import TextInput, Select
66

7-
from django_filters.widgets import BooleanWidget
7+
from django_filters.widgets import BooleanWidget, QueryArrayWidget
88
from django_filters.widgets import BaseCSVWidget
99
from django_filters.widgets import CSVWidget
1010
from django_filters.widgets import RangeWidget
@@ -279,3 +279,74 @@ def test_widget(self):
279279

280280
self.assertHTMLEqual(w.render('price', [1, 2]), """
281281
<input type="text" name="price" value="1,2" />""")
282+
283+
284+
class QueryArrayWidgetTests(TestCase):
285+
286+
def test_widget_value_from_datadict(self):
287+
w = QueryArrayWidget()
288+
289+
# Values can be provided as csv string: ?foo=bar,baz
290+
data = {'price': None}
291+
result = w.value_from_datadict(data, {}, 'price')
292+
self.assertEqual(result, [])
293+
294+
data = {'price': '1'}
295+
result = w.value_from_datadict(data, {}, 'price')
296+
self.assertEqual(result, ['1'])
297+
298+
data = {'price': '1,2'}
299+
result = w.value_from_datadict(data, {}, 'price')
300+
self.assertEqual(result, ['1', '2'])
301+
302+
data = {'price': '1,,2'}
303+
result = w.value_from_datadict(data, {}, 'price')
304+
self.assertEqual(result, ['1', '2'])
305+
306+
data = {'price': '1,'}
307+
result = w.value_from_datadict(data, {}, 'price')
308+
self.assertEqual(result, ['1'])
309+
310+
data = {'price': ','}
311+
result = w.value_from_datadict(data, {}, 'price')
312+
self.assertEqual(result, [])
313+
314+
data = {'price': ''}
315+
result = w.value_from_datadict(data, {}, 'price')
316+
self.assertEqual(result, [])
317+
318+
result = w.value_from_datadict({}, {}, 'price')
319+
self.assertEqual(result, [])
320+
321+
# Values can be provided as query array: ?foo[]=bar&foo[]=baz
322+
323+
data = {'price[]': None}
324+
result = w.value_from_datadict(data, {}, 'price')
325+
self.assertEqual(result, [])
326+
327+
data = {'price[]': ['1']}
328+
result = w.value_from_datadict(data, {}, 'price')
329+
self.assertEqual(result, ['1'])
330+
331+
data = {'price[]': ['1', '2']}
332+
result = w.value_from_datadict(data, {}, 'price')
333+
self.assertEqual(result, ['1', '2'])
334+
335+
data = {'price[]': ['1', '', '2']}
336+
result = w.value_from_datadict(data, {}, 'price')
337+
self.assertEqual(result, ['1', '2'])
338+
339+
data = {'price[]': ['1', '']}
340+
result = w.value_from_datadict(data, {}, 'price')
341+
self.assertEqual(result, ['1'])
342+
343+
data = {'price[]': ['', '']}
344+
result = w.value_from_datadict(data, {}, 'price')
345+
self.assertEqual(result, [])
346+
347+
data = {'price[]': []}
348+
result = w.value_from_datadict(data, {}, 'price')
349+
self.assertEqual(result, [])
350+
351+
result = w.value_from_datadict({}, {}, 'price')
352+
self.assertEqual(result, [])

0 commit comments

Comments
 (0)