Skip to content

Commit

Permalink
Update {Range,LookupType}Widgets to use suffixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan P Kilby committed Sep 1, 2017
1 parent cbc566a commit 1f2f13d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 62 deletions.
11 changes: 10 additions & 1 deletion django_filters/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@

from .conf import settings
from .utils import handle_timezone
from .widgets import BaseCSVWidget, CSVWidget, LookupTypeWidget, RangeWidget
from .widgets import (
BaseCSVWidget,
CSVWidget,
DateRangeWidget,
LookupTypeWidget,
RangeWidget
)


class RangeField(forms.MultiValueField):
Expand All @@ -31,6 +37,7 @@ def compress(self, data_list):


class DateRangeField(RangeField):
widget = DateRangeWidget

def __init__(self, *args, **kwargs):
fields = (
Expand All @@ -56,6 +63,7 @@ def compress(self, data_list):


class DateTimeRangeField(RangeField):
widget = DateRangeWidget

def __init__(self, *args, **kwargs):
fields = (
Expand All @@ -65,6 +73,7 @@ def __init__(self, *args, **kwargs):


class TimeRangeField(RangeField):
widget = DateRangeWidget

def __init__(self, *args, **kwargs):
fields = (
Expand Down
15 changes: 13 additions & 2 deletions django_filters/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,20 @@ def decompress(self, value):
return value


class RangeWidget(forms.MultiWidget):
class RangeWidget(SuffixedMultiWidget):
template_name = 'django_filters/widgets/multiwidget.html'
suffixes = ['min', 'max']

def __init__(self, attrs=None):
widgets = (forms.TextInput, forms.TextInput)
super(RangeWidget, self).__init__(widgets, attrs)

def format_output(self, rendered_widgets):
# Method was removed in Django 1.11.
rendered_widgets = [
self.replace_name(output, i)
for i, output in enumerate(rendered_widgets)
]
return '-'.join(rendered_widgets)

def decompress(self, value):
Expand All @@ -157,7 +162,13 @@ def decompress(self, value):
return [None, None]


class LookupTypeWidget(forms.MultiWidget):
class DateRangeWidget(RangeWidget):
suffixes = ['after', 'before']


class LookupTypeWidget(SuffixedMultiWidget):
suffixes = [None, 'lookup']

def decompress(self, value):
if value is None:
return [None, None]
Expand Down
30 changes: 15 additions & 15 deletions docs/ref/filters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -470,13 +470,13 @@ Filters where a value is between two numerical values, or greater than a minimum
qs = Book.objects.all().order_by('title')

# Range: Books between 5€ and 15€
f = F({'price_0': '5', 'price_1': '15'}, queryset=qs)
f = F({'price_min': '5', 'price_max': '15'}, queryset=qs)

# Min-Only: Books costing more the 11€
f = F({'price_0': '11'}, queryset=qs)
f = F({'price_min': '11'}, queryset=qs)

# Max-Only: Books costing less than 19€
f = F({'price_1': '19'}, queryset=qs)
f = F({'price_max': '19'}, queryset=qs)


``DateRangeFilter``
Expand Down Expand Up @@ -504,13 +504,13 @@ Example of using the ``DateField`` field::
fields = ['date']

# Range: Comments added between 2016-01-01 and 2016-02-01
f = F({'date_0': '2016-01-01', 'date_1': '2016-02-01'})
f = F({'date_after': '2016-01-01', 'date_before': '2016-02-01'})

# Min-Only: Comments added after 2016-01-01
f = F({'date_0': '2016-01-01'})
f = F({'date_after': '2016-01-01'})

# Max-Only: Comments added before 2016-02-01
f = F({'date_1': '2016-02-01'})
f = F({'date_before': '2016-02-01'})

.. note::
When filtering ranges that occurs on DST transition dates ``DateFromToRangeFilter`` will use the first valid hour of the day for start datetime and the last valid hour of the day for end datetime.
Expand All @@ -537,15 +537,15 @@ Example of using the ``DateTimeField`` field::
Article.objects.create(published='2016-02-10 12:00')

# Range: Articles published between 2016-01-01 and 2016-02-01
f = F({'published_0': '2016-01-01', 'published_1': '2016-02-01'})
f = F({'published_after': '2016-01-01', 'published_before': '2016-02-01'})
assert len(f.qs) == 2

# Min-Only: Articles published after 2016-01-01
f = F({'published_0': '2016-01-01'})
f = F({'published_after': '2016-01-01'})
assert len(f.qs) == 3

# Max-Only: Articles published before 2016-02-01
f = F({'published_1': '2016-02-01'})
f = F({'published_before': '2016-02-01'})
assert len(f.qs) == 2

``DateTimeFromToRangeFilter``
Expand All @@ -570,15 +570,15 @@ Example::
Article.objects.create(published='2016-01-02 8:00')

# Range: Articles published 2016-01-01 between 8:00 and 10:00
f = F({'published_0': '2016-01-01 8:00', 'published_1': '2016-01-01 10:00'})
f = F({'published_after': '2016-01-01 8:00', 'published_before': '2016-01-01 10:00'})
assert len(f.qs) == 2

# Min-Only: Articles published after 2016-01-01 8:00
f = F({'published_0': '2016-01-01 8:00'})
f = F({'published_after': '2016-01-01 8:00'})
assert len(f.qs) == 3

# Max-Only: Articles published before 2016-01-01 10:00
f = F({'published_1': '2016-01-01 10:00'})
f = F({'published_before': '2016-01-01 10:00'})
assert len(f.qs) == 2

``TimeRangeFilter``
Expand All @@ -600,13 +600,13 @@ Example::
fields = ['time']

# Range: Comments added between 8:00 and 10:00
f = F({'time_0': '8:00', 'time_1': '10:00'})
f = F({'time_after': '8:00', 'time_before': '10:00'})

# Min-Only: Comments added after 8:00
f = F({'time_0': '8:00'})
f = F({'time_after': '8:00'})

# Max-Only: Comments added before 10:00
f = F({'time_1': '10:00'})
f = F({'time_before': '10:00'})

``AllValuesFilter``
~~~~~~~~~~~~~~~~~~~
Expand Down
8 changes: 4 additions & 4 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ def test_render_used_html5(self):
inner = forms.DecimalField()
f = LookupTypeField(inner, [('gt', 'gt'), ('lt', 'lt')])
self.assertHTMLEqual(f.widget.render('price', ''), """
<input type="number" step="any" name="price_0" />
<select name="price_1">
<input type="number" step="any" name="price" />
<select name="price_lookup">
<option value="gt">gt</option>
<option value="lt">lt</option>
</select>""")
self.assertHTMLEqual(f.widget.render('price', ['abc', 'lt']), """
<input type="number" step="any" name="price_0" value="abc" />
<select name="price_1">
<input type="number" step="any" name="price" value="abc" />
<select name="price_lookup">
<option value="gt">gt</option>
<option selected="selected" value="lt">lt</option>
</select>""")
Expand Down
52 changes: 26 additions & 26 deletions tests/test_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,11 +742,11 @@ class Meta:
fields = ['price']

qs = Book.objects.all()
f = F({'price_0': '15', 'price_1': 'lt'}, queryset=qs)
f = F({'price': '15', 'price_lookup': 'lt'}, queryset=qs)
self.assertQuerysetEqual(f.qs, ['Ender\'s Game'], lambda o: o.title)
f = F({'price_0': '15', 'price_1': 'lt'})
f = F({'price': '15', 'price_lookup': 'lt'})
self.assertQuerysetEqual(f.qs, ['Ender\'s Game'], lambda o: o.title)
f = F({'price_0': '', 'price_1': 'lt'})
f = F({'price': '', 'price_lookup': 'lt'})
self.assertQuerysetEqual(f.qs,
['Ender\'s Game', 'Rainbow Six', 'Snowcrash'],
lambda o: o.title, ordered=False)
Expand All @@ -758,7 +758,7 @@ class Meta:
model = Book
fields = ['price']

f = F({'price_0': '15'})
f = F({'price': '15'})
self.assertQuerysetEqual(f.qs, ['Rainbow Six'], lambda o: o.title)


Expand Down Expand Up @@ -789,29 +789,29 @@ class Meta:
self.assertQuerysetEqual(f.qs,
['Ender\'s Game', 'Free Book', 'Rainbow Six', 'Refund', 'Snowcrash'],
lambda o: o.title)
f = F({'price_0': '5', 'price_1': '15'}, queryset=qs)
f = F({'price_min': '5', 'price_max': '15'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Ender\'s Game', 'Rainbow Six'],
lambda o: o.title)

f = F({'price_0': '11'}, queryset=qs)
f = F({'price_min': '11'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Rainbow Six', 'Snowcrash'],
lambda o: o.title)
f = F({'price_1': '19'}, queryset=qs)
f = F({'price_max': '19'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Ender\'s Game', 'Free Book', 'Rainbow Six', 'Refund'],
lambda o: o.title)

f = F({'price_0': '0', 'price_1': '12'}, queryset=qs)
f = F({'price_min': '0', 'price_max': '12'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Ender\'s Game', 'Free Book'],
lambda o: o.title)
f = F({'price_0': '-11', 'price_1': '0'}, queryset=qs)
f = F({'price_min': '-11', 'price_max': '0'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Free Book', 'Refund'],
lambda o: o.title)
f = F({'price_0': '0', 'price_1': '0'}, queryset=qs)
f = F({'price_min': '0', 'price_max': '0'}, queryset=qs)
self.assertQuerysetEqual(f.qs,
['Free Book'],
lambda o: o.title)
Expand Down Expand Up @@ -914,8 +914,8 @@ class Meta:
fields = ['date']

results = F(data={
'published_0': '2016-01-02',
'published_1': '2016-01-03'})
'published_after': '2016-01-02',
'published_before': '2016-01-03'})
self.assertEqual(len(results.qs), 3)

def test_filtering_ignores_time(self):
Expand All @@ -937,8 +937,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2016-01-02',
'published_1': '2016-01-03'})
'published_after': '2016-01-02',
'published_before': '2016-01-03'})
self.assertEqual(len(results.qs), 3)

@unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
Expand All @@ -958,8 +958,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2017-10-15',
'published_1': '2017-10-15'})
'published_after': '2017-10-15',
'published_before': '2017-10-15'})
self.assertEqual(len(results.qs), 2)

@unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
Expand All @@ -979,8 +979,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2017-02-18',
'published_1': '2017-02-18'})
'published_after': '2017-02-18',
'published_before': '2017-02-18'})
self.assertEqual(len(results.qs), 2)

@unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
Expand All @@ -1001,8 +1001,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2017-3-26',
'published_1': '2017-3-26'})
'published_after': '2017-3-26',
'published_before': '2017-3-26'})
self.assertEqual(len(results.qs), 3)

@unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
Expand All @@ -1023,8 +1023,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2017-10-29',
'published_1': '2017-10-29'})
'published_after': '2017-10-29',
'published_before': '2017-10-29'})
self.assertEqual(len(results.qs), 3)


Expand All @@ -1049,8 +1049,8 @@ class Meta:
fields = ['published']

results = F(data={
'published_0': '2016-01-02 10:00',
'published_1': '2016-01-03 19:00'})
'published_after': '2016-01-02 10:00',
'published_before': '2016-01-03 19:00'})
self.assertEqual(len(results.qs), 2)


Expand All @@ -1073,8 +1073,8 @@ class Meta:
fields = ['time']

results = F(data={
'time_0': '8:00',
'time_1': '10:00'})
'time_after': '8:00',
'time_before': '10:00'})
self.assertEqual(len(results.qs), 2)


Expand Down
27 changes: 13 additions & 14 deletions tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ def test_widget_render(self):
widgets = [TextInput(), Select(choices=(('a', 'a'), ('b', 'b')))]
w = LookupTypeWidget(widgets)
self.assertHTMLEqual(w.render('price', ''), """
<input name="price_0" type="text" />
<select name="price_1">
<input name="price" type="text" />
<select name="price_lookup">
<option value="a">a</option>
<option value="b">b</option>
</select>""")

self.assertHTMLEqual(w.render('price', None), """
<input name="price_0" type="text" />
<select name="price_1">
<input name="price" type="text" />
<select name="price_lookup">
<option value="a">a</option>
<option value="b">b</option>
</select>""")

self.assertHTMLEqual(w.render('price', ['2', 'a']), """
<input name="price_0" type="text" value="2" />
<select name="price_1">
<input name="price" type="text" value="2" />
<select name="price_lookup">
<option selected="selected" value="a">a</option>
<option value="b">b</option>
</select>""")
Expand Down Expand Up @@ -194,27 +194,26 @@ def test_widget(self):
w = RangeWidget()
self.assertEqual(len(w.widgets), 2)
self.assertHTMLEqual(w.render('price', ''), """
<input type="text" name="price_0" />
<input type="text" name="price_min" />
-
<input type="text" name="price_1" />""")
<input type="text" name="price_max" />""")

self.assertHTMLEqual(w.render('price', slice(5.99, 9.99)), """
<input type="text" name="price_0" value="5.99" />
<input type="text" name="price_min" value="5.99" />
-
<input type="text" name="price_1" value="9.99" />""")
<input type="text" name="price_max" value="9.99" />""")

def test_widget_attributes(self):
w = RangeWidget(attrs={'type': 'date'})
self.assertEqual(len(w.widgets), 2)
self.assertHTMLEqual(w.render('date', ''), """
<input type="date" name="date_0" />
<input type="date" name="date_min" />
-
<input type="date" name="date_1" />""")
<input type="date" name="date_max" />""")


class BooleanWidgetTests(TestCase):
"""
"""

def test_widget_render(self):
w = BooleanWidget()
self.assertHTMLEqual(w.render('price', ''), """
Expand Down

0 comments on commit 1f2f13d

Please sign in to comment.