From 685d956764e6c76d1834274f3afa6ef0ce5d85a1 Mon Sep 17 00:00:00 2001 From: Nasir Hussain Date: Mon, 16 Sep 2019 22:29:13 +0500 Subject: [PATCH] [3.0.x] Fixed #30758 -- Made RangeFields use multiple hidden inputs for initial data. Backport of faf4b988fe75dd4045bc5c62496cc4f2e0db8c4d from master. --- django/contrib/postgres/forms/ranges.py | 34 +++++++++++++++---------- tests/postgres_tests/test_ranges.py | 19 ++++++++++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/django/contrib/postgres/forms/ranges.py b/django/contrib/postgres/forms/ranges.py index c36bec8479..1e3011caad 100644 --- a/django/contrib/postgres/forms/ranges.py +++ b/django/contrib/postgres/forms/ranges.py @@ -4,21 +4,40 @@ from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange from django import forms from django.core import exceptions -from django.forms.widgets import MultiWidget +from django.forms.widgets import HiddenInput, MultiWidget from django.utils.deprecation import RemovedInDjango31Warning from django.utils.translation import gettext_lazy as _ __all__ = [ 'BaseRangeField', 'IntegerRangeField', 'DecimalRangeField', - 'DateTimeRangeField', 'DateRangeField', 'FloatRangeField', 'RangeWidget', + 'DateTimeRangeField', 'DateRangeField', 'FloatRangeField', + 'HiddenRangeWidget', 'RangeWidget', ] +class RangeWidget(MultiWidget): + def __init__(self, base_widget, attrs=None): + widgets = (base_widget, base_widget) + super().__init__(widgets, attrs) + + def decompress(self, value): + if value: + return (value.lower, value.upper) + return (None, None) + + +class HiddenRangeWidget(RangeWidget): + """A widget that splits input into two inputs.""" + def __init__(self, attrs=None): + super().__init__(HiddenInput, attrs) + + class BaseRangeField(forms.MultiValueField): default_error_messages = { 'invalid': _('Enter two valid values.'), 'bound_ordering': _('The start of the range must not exceed the end of the range.'), } + hidden_widget = HiddenRangeWidget def __init__(self, **kwargs): if 'widget' not in kwargs: @@ -96,14 +115,3 @@ class DateRangeField(BaseRangeField): default_error_messages = {'invalid': _('Enter two valid dates.')} base_field = forms.DateField range_type = DateRange - - -class RangeWidget(MultiWidget): - def __init__(self, base_widget, attrs=None): - widgets = (base_widget, base_widget) - super().__init__(widgets, attrs) - - def decompress(self, value): - if value: - return (value.lower, value.upper) - return (None, None) diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py index 89f32ee77c..74f1ec0ff8 100644 --- a/tests/postgres_tests/test_ranges.py +++ b/tests/postgres_tests/test_ranges.py @@ -5,6 +5,7 @@ from decimal import Decimal from django import forms from django.core import exceptions, serializers from django.db.models import DateField, DateTimeField, F, Func, Value +from django.http import QueryDict from django.test import ignore_warnings, override_settings from django.utils import timezone from django.utils.deprecation import RemovedInDjango31Warning @@ -512,6 +513,24 @@ class TestFormField(PostgreSQLSimpleTestCase): value = field.clean(['', '']) self.assertIsNone(value) + def test_datetime_form_initial_data(self): + class DateTimeRangeForm(forms.Form): + datetime_field = pg_forms.DateTimeRangeField(show_hidden_initial=True) + + data = QueryDict(mutable=True) + data.update({ + 'datetime_field_0': '2010-01-01 11:13:00', + 'datetime_field_1': '', + 'initial-datetime_field_0': '2010-01-01 10:12:00', + 'initial-datetime_field_1': '', + }) + form = DateTimeRangeForm(data=data) + self.assertTrue(form.has_changed()) + + data['initial-datetime_field_0'] = '2010-01-01 11:13:00' + form = DateTimeRangeForm(data=data) + self.assertFalse(form.has_changed()) + def test_rendering(self): class RangeForm(forms.Form): ints = pg_forms.IntegerRangeField()