From 00e22063ae9c17de6b5867d086e6bcc7b51d6f5c Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 16 Jul 2020 14:34:19 +0200 Subject: [PATCH] misc: use Django native split datetime field (#45108) --- chrono/manager/forms.py | 16 ++- .../manager_time_period_exception_form.html | 4 +- .../templates/chrono/splitdatetime.html | 9 ++ .../templates/chrono/widget_datetime.html | 4 - chrono/manager/widgets.py | 34 ++---- tests/test_manager.py | 110 +++++++++--------- tests/test_misc.py | 6 - 7 files changed, 89 insertions(+), 94 deletions(-) create mode 100644 chrono/manager/templates/chrono/splitdatetime.html delete mode 100644 chrono/manager/templates/chrono/widget_datetime.html delete mode 100644 tests/test_misc.py diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index db5da10..e2244d7 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -42,7 +42,7 @@ from chrono.agendas.models import ( ) from . import widgets -from .widgets import DateTimeWidget +from .widgets import SplitDateTimeField class AgendaAddForm(forms.ModelForm): @@ -87,10 +87,12 @@ class NewEventForm(forms.ModelForm): model = Event widgets = { 'agenda': forms.HiddenInput(), - 'start_datetime': DateTimeWidget(), 'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), } exclude = ['full', 'meeting_type', 'desk', 'slug', 'resources'] + field_classes = { + 'start_datetime': SplitDateTimeField, + } class EventForm(forms.ModelForm): @@ -98,9 +100,11 @@ class EventForm(forms.ModelForm): model = Event widgets = { 'agenda': forms.HiddenInput(), - 'start_datetime': DateTimeWidget(), 'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), } + field_classes = { + 'start_datetime': SplitDateTimeField, + } exclude = ['full', 'meeting_type', 'desk', 'resources'] @@ -230,8 +234,10 @@ class TimePeriodExceptionForm(forms.ModelForm): fields = ['desk', 'start_datetime', 'end_datetime', 'label'] widgets = { 'desk': forms.HiddenInput(), - 'start_datetime': DateTimeWidget(), - 'end_datetime': DateTimeWidget(), + } + field_classes = { + 'start_datetime': SplitDateTimeField, + 'end_datetime': SplitDateTimeField, } def clean(self): diff --git a/chrono/manager/templates/chrono/manager_time_period_exception_form.html b/chrono/manager/templates/chrono/manager_time_period_exception_form.html index f3e708d..0a17ec9 100644 --- a/chrono/manager/templates/chrono/manager_time_period_exception_form.html +++ b/chrono/manager/templates/chrono/manager_time_period_exception_form.html @@ -60,9 +60,9 @@ if ($start_datetime.val()) { var new_date = new Date($start_datetime.val()); new_date.setDate(new_date.getDate() + 1); - $('[name="start_datetime$time"]').val('00:00'); + $('[name="start_datetime_1"]').val('00:00'); $('[name="end_datetime$date"]').val(new_date.toISOString().substring(0, 10)); - $('[name="end_datetime$time"]').val('00:00'); + $('[name="end_datetime_1"]').val('00:00'); } }); diff --git a/chrono/manager/templates/chrono/splitdatetime.html b/chrono/manager/templates/chrono/splitdatetime.html new file mode 100644 index 0000000..8593d86 --- /dev/null +++ b/chrono/manager/templates/chrono/splitdatetime.html @@ -0,0 +1,9 @@ + +{% with widget=widget.subwidgets.0 %} + +{% endwith %} +{% with widget=widget.subwidgets.1 %} + + +{% endwith %} + diff --git a/chrono/manager/templates/chrono/widget_datetime.html b/chrono/manager/templates/chrono/widget_datetime.html deleted file mode 100644 index 44c0118..0000000 --- a/chrono/manager/templates/chrono/widget_datetime.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/chrono/manager/widgets.py b/chrono/manager/widgets.py index cd24ff5..26adcc1 100644 --- a/chrono/manager/widgets.py +++ b/chrono/manager/widgets.py @@ -15,35 +15,21 @@ # along with this program. If not, see . -import datetime - -from django.forms.widgets import DateTimeInput, TimeInput, SelectMultiple -from django.utils import dateparse +from django.forms.fields import SplitDateTimeField +from django.forms.widgets import TimeInput, SelectMultiple, SplitDateTimeWidget from django.utils.safestring import mark_safe -class DateTimeWidget(DateTimeInput): - template_name = 'chrono/widget_datetime.html' +class SplitDateTimeWidget(SplitDateTimeWidget): + template_name = 'chrono/splitdatetime.html' - def format_value(self, value): - if value: - x = { - 'date': value.date().strftime('%Y-%m-%d'), - 'time': value.time().strftime('%H:%M'), - } - return x - return None + def __init__(self, *args, **kwargs): + kwargs['time_format'] = '%H:%M' + super().__init__(*args, **kwargs) - def value_from_datadict(self, data, files, name): - date_string = data.get(name + '$date') - time_string = data.get(name + '$time') - if not date_string or not time_string: - return None - date_value = dateparse.parse_date(date_string) - time_value = dateparse.parse_time(time_string) - if not date_value or not time_value: - return None - return datetime.datetime.combine(date_value, time_value) + +class SplitDateTimeField(SplitDateTimeField): + widget = SplitDateTimeWidget class TimeWidget(TimeInput): diff --git a/tests/test_manager.py b/tests/test_manager.py index 0f864de..af736ba 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -901,8 +901,8 @@ def test_add_event(app, admin_user): assert "This agenda doesn't have any event yet." in resp.text year = now().year + 1 resp = resp.click('New Event') - resp.form['start_datetime$date'] = '%s-02-15' % year - resp.form['start_datetime$time'] = '17:00' + resp.form['start_datetime_0'] = '%s-02-15' % year + resp.form['start_datetime_1'] = '17:00' resp.form['places'] = 10 resp = resp.form.submit() resp = resp.follow() @@ -920,8 +920,8 @@ def test_add_event(app, admin_user): # add with a description resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200) resp = resp.click('New Event') - resp.form['start_datetime$date'] = '%s-02-15' % year - resp.form['start_datetime$time'] = '18:00' + resp.form['start_datetime_0'] = '%s-02-15' % year + resp.form['start_datetime_1'] = '18:00' resp.form['publication_date'] = '2020-05-11' resp.form['places'] = 11 resp.form['description'] = 'A description' @@ -941,11 +941,15 @@ def test_add_event(app, admin_user): ): resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200) resp = resp.click('New Event') - resp.form['start_datetime$date'] = parts[0] - resp.form['start_datetime$time'] = parts[1] + resp.form['start_datetime_0'] = parts[0] + resp.form['start_datetime_1'] = parts[1] resp.form['places'] = 10 resp = resp.form.submit() - assert resp.text.count('This field is required.') == 1 + assert ( + resp.text.count('Enter a valid date') + or resp.text.count('Enter a valid time') == 1 + or resp.text.count('This field is required.') == 1 + ) def test_add_event_on_missing_agenda(app, admin_user): @@ -968,8 +972,8 @@ def test_add_event_as_manager(app, manager_user): resp = resp.click('Settings') assert '

Settings' in resp.text resp = resp.click('New Event') - resp.form['start_datetime$date'] = '2016-02-15' - resp.form['start_datetime$time'] = '17:00' + resp.form['start_datetime_0'] = '2016-02-15' + resp.form['start_datetime_1'] = '17:00' resp.form['places'] = 10 resp = resp.form.submit() resp = resp.follow() @@ -982,8 +986,8 @@ def test_add_event_as_manager(app, manager_user): assert event.end_datetime is None resp = resp.click('New Event') - resp.form['start_datetime$date'] = '2016-02-15' - resp.form['start_datetime$time'] = '17:00' + resp.form['start_datetime_0'] = '2016-02-15' + resp.form['start_datetime_1'] = '17:00' resp.form['duration'] = 45 resp.form['places'] = 12 resp = resp.form.submit() @@ -1003,12 +1007,12 @@ def test_edit_event(app, admin_user): app = login(app) resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200) resp = resp.click('Feb. 15, 2016, 5 p.m.') - assert resp.form['start_datetime$date'].value == '2016-02-15' - assert resp.form['start_datetime$time'].value == '17:00' + assert resp.form['start_datetime_0'].value == '2016-02-15' + assert resp.form['start_datetime_1'].value == '17:00' assert resp.form['publication_date'].value == '' assert resp.form['duration'].value == '' - resp.form['start_datetime$date'] = '2016-02-16' - resp.form['start_datetime$time'] = '17:00' + resp.form['start_datetime_0'] = '2016-02-16' + resp.form['start_datetime_1'] = '17:00' resp.form['publication_date'] = '2020-05-11' resp.form['duration'].value = 45 resp.form['places'] = 20 @@ -1045,11 +1049,11 @@ def test_edit_event_as_manager(app, manager_user): agenda.save() resp = app.get('/manage/agendas/%s/settings' % agenda.id, status=200) resp = resp.click('Feb. 15, 2016, 5 p.m.') - assert resp.form['start_datetime$date'].value == '2016-02-15' - assert resp.form['start_datetime$time'].value == '17:00' + assert resp.form['start_datetime_0'].value == '2016-02-15' + assert resp.form['start_datetime_1'].value == '17:00' assert resp.form['publication_date'].value == '2020-05-11' - resp.form['start_datetime$date'] = '2016-02-16' - resp.form['start_datetime$time'] = '17:00' + resp.form['start_datetime_0'] = '2016-02-16' + resp.form['start_datetime_1'] = '17:00' resp.form['publication_date'] = '' resp.form['places'] = 20 resp = resp.form.submit() @@ -1679,10 +1683,10 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user): tomorrow = make_aware(today + datetime.timedelta(days=1)) dt_format = '%Y-%m-%d %H:%M' resp.form['label'] = 'Exception 1' - resp.form['start_datetime$date'] = tomorrow.strftime('%Y-%m-%d') - resp.form['start_datetime$time'] = '08:00' - resp.form['end_datetime$date'] = tomorrow.strftime('%Y-%m-%d') - resp.form['end_datetime$time'] = '16:00' + resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d') + resp.form['start_datetime_1'] = '08:00' + resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d') + resp.form['end_datetime_1'] = '16:00' resp = resp.form.submit().follow() assert TimePeriodException.objects.count() == 1 time_period_exception = TimePeriodException.objects.first() @@ -1696,10 +1700,10 @@ def test_meetings_agenda_add_time_period_exception(app, admin_user): resp = resp.click('Add a time period exception', index=1) future = tomorrow + datetime.timedelta(days=15) resp.form['label'] = 'Exception 2' - resp.form['start_datetime$date'] = future.strftime('%Y-%m-%d') - resp.form['start_datetime$time'] = '00:00' - resp.form['end_datetime$date'] = future.strftime('%Y-%m-%d') - resp.form['end_datetime$time'] = '16:00' + resp.form['start_datetime_0'] = future.strftime('%Y-%m-%d') + resp.form['start_datetime_1'] = '00:00' + resp.form['end_datetime_0'] = future.strftime('%Y-%m-%d') + resp.form['end_datetime_1'] = '16:00' resp = resp.form.submit().follow() assert TimePeriodException.objects.count() == 2 assert 'Exception 1' in resp.text @@ -1728,10 +1732,10 @@ def test_meetings_agenda_add_time_period_exception_when_booking_exists(app, admi # fields should be marked with errors assert resp.text.count('This field is required.') == 2 # try again with data in fields - resp.form['start_datetime$date'] = '2017-05-22' - resp.form['start_datetime$time'] = '08:00' - resp.form['end_datetime$date'] = '2017-05-26' - resp.form['end_datetime$time'] = '17:30' + resp.form['start_datetime_0'] = '2017-05-22' + resp.form['start_datetime_1'] = '08:00' + resp.form['end_datetime_0'] = '2017-05-26' + resp.form['end_datetime_1'] = '17:30' resp = resp.form.submit().follow() assert 'Exception added. Note: one or several bookings exists within this time slot.' in resp.text assert TimePeriodException.objects.count() == 1 @@ -1754,10 +1758,10 @@ def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists resp = app.get('/manage/agendas/%d/' % agenda.pk).follow() resp = resp.click('Settings') resp = resp.click('Add a time period exception') - resp.form['start_datetime$date'] = '2017-05-22' - resp.form['start_datetime$time'] = '08:00' - resp.form['end_datetime$date'] = '2017-05-26' - resp.form['end_datetime$time'] = '17:30' + resp.form['start_datetime_0'] = '2017-05-22' + resp.form['start_datetime_1'] = '08:00' + resp.form['end_datetime_0'] = '2017-05-26' + resp.form['end_datetime_1'] = '17:30' resp = resp.form.submit().follow() assert 'Exception added. Note: one or several bookings exists within this time slot.' not in resp.text assert TimePeriodException.objects.count() == 1 @@ -1766,10 +1770,10 @@ def test_meetings_agenda_add_time_period_exception_when_cancelled_booking_exists def test_meetings_agenda_add_invalid_time_period_exception(): form = TimePeriodExceptionForm( data={ - 'start_datetime$date': '2017-05-26', - 'start_datetime$time': '17:30', - 'end_datetime$date': '2017-05-22', - 'end_datetime$time': '08:00', + 'start_datetime_0': '2017-05-26', + 'start_datetime_1': '17:30', + 'end_datetime_0': '2017-05-22', + 'end_datetime_1': '08:00', } ) assert form.is_valid() is False @@ -1778,10 +1782,10 @@ def test_meetings_agenda_add_invalid_time_period_exception(): # start_datetime is invalid form = TimePeriodExceptionForm( data={ - 'start_datetime$date': '2017-05-26', - 'start_datetime$time': 'foo', - 'end_datetime$date': '2017-05-22', - 'end_datetime$time': '08:00', + 'start_datetime_0': '2017-05-26', + 'start_datetime_1': 'foo', + 'end_datetime_0': '2017-05-22', + 'end_datetime_1': '08:00', } ) assert form.is_valid() is False @@ -1789,10 +1793,10 @@ def test_meetings_agenda_add_invalid_time_period_exception(): # end_datetime is invalid form = TimePeriodExceptionForm( data={ - 'start_datetime$date': '2017-05-26', - 'start_datetime$time': '17:30', - 'end_datetime$date': 'bar', - 'end_datetime$time': '08:00', + 'start_datetime_0': '2017-05-26', + 'start_datetime_1': '17:30', + 'end_datetime_0': 'bar', + 'end_datetime_1': '08:00', } ) assert form.is_valid() is False @@ -1813,10 +1817,10 @@ def test_meetings_agenda_delete_time_period_exception(app, admin_user): tomorrow = make_aware(today + datetime.timedelta(days=15)) dt_format = '%Y-%m-%d %H:%M' resp.form['label'] = 'Exception 1' - resp.form['start_datetime$date'] = tomorrow.strftime('%Y-%m-%d') - resp.form['start_datetime$time'] = '08:00' - resp.form['end_datetime$date'] = tomorrow.strftime('%Y-%m-%d') - resp.form['end_datetime$time'] = '16:00' + resp.form['start_datetime_0'] = tomorrow.strftime('%Y-%m-%d') + resp.form['start_datetime_1'] = '08:00' + resp.form['end_datetime_0'] = tomorrow.strftime('%Y-%m-%d') + resp.form['end_datetime_1'] = '16:00' resp = resp.form.submit().follow() assert TimePeriodException.objects.count() == 1 time_period_exception = TimePeriodException.objects.first() @@ -2857,8 +2861,8 @@ def test_agenda_view_edit_event(app, manager_user): resp = app.get(event_url) assert 'Options' in resp.text resp = resp.click('Options') - resp.form['start_datetime$date'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d') - resp.form['start_datetime$time'] = agenda.event_set.first().start_datetime.strftime('%H:%M') + resp.form['start_datetime_0'] = agenda.event_set.first().start_datetime.strftime('%Y-%m-%d') + resp.form['start_datetime_1'] = agenda.event_set.first().start_datetime.strftime('%H:%M') resp = resp.form.submit(status=302).follow() assert event_url == resp.request.url diff --git a/tests/test_misc.py b/tests/test_misc.py deleted file mode 100644 index c2610b1..0000000 --- a/tests/test_misc.py +++ /dev/null @@ -1,6 +0,0 @@ -from chrono.manager.widgets import DateTimeWidget, TimeWidget - - -def test_widgets_init(): - DateTimeWidget() - TimeWidget() -- 2.27.0