Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update {Range,LookupType}Widgets to use suffixes #770

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion django_filters/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,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 @@ -28,6 +34,7 @@ def compress(self, data_list):


class DateRangeField(RangeField):
widget = DateRangeWidget

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


class DateTimeRangeField(RangeField):
widget = DateRangeWidget

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


class TimeRangeField(RangeField):
widget = DateRangeWidget

def __init__(self, *args, **kwargs):
fields = (
Expand Down
11 changes: 9 additions & 2 deletions django_filters/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ 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)
Expand All @@ -136,7 +137,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
8 changes: 8 additions & 0 deletions docs/guide/migration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ been removed.
To alter strictness behavior, the appropriate view code should be overridden.
More details will be provided in future docs.

``MultiWidget`` replaced by ``SuffixedMultiWidget``
---------------------------------------------------

``RangeWidget``, ``DateRangeWidget``, and ``LookupTypeWidget`` now inherit from
``SuffixedMultiWidget``, changing the suffixes of their query param names. For
example, ``RangeWidget`` now has ``_min`` and ``_max`` suffixes instead of
``_0`` and ``_1``.


----------------
Migrating to 1.0
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 @@ -123,14 +123,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 @@ -738,11 +738,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 @@ -754,7 +754,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 @@ -785,29 +785,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 @@ -910,8 +910,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 @@ -933,8 +933,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)

@override_settings(TIME_ZONE='America/Sao_Paulo')
Expand All @@ -953,8 +953,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)

@override_settings(TIME_ZONE='America/Sao_Paulo')
Expand All @@ -973,8 +973,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)

@override_settings(TIME_ZONE='Europe/Paris')
Expand All @@ -994,8 +994,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)

@override_settings(TIME_ZONE='Europe/Paris')
Expand All @@ -1015,8 +1015,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 @@ -1041,8 +1041,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 @@ -1065,8 +1065,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 @@ -23,22 +23,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 @@ -192,27 +192,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