summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Burrows <stephen.r.burrows@gmail.com>2014-05-06 18:14:06 -0700
committerClaude Paroz <claude@2xlibre.net>2014-05-10 10:58:51 +0200
commit0c198035e958a3caa0bd1e0fd9f419bf1308399d (patch)
tree5ac1c255c7e95e529949ceb8fe59d2ae05d009e1
parent8a090c21f10c503dd5f29885e78bfb0cb5588ba4 (diff)
[1.7.x] Fixed #22502 -- Fixed microseconds/default/form interaction
Made explicit lack of microsecond handling by built-in datetime form fields. Used that explicitness to appropriately nix microsecond values in bound fields. Thanks Claude Paroz for the review. Backport of a5de0df58 from master.
-rw-r--r--AUTHORS1
-rw-r--r--django/forms/forms.py6
-rw-r--r--django/forms/widgets.py2
-rw-r--r--tests/forms_tests/tests/test_forms.py29
4 files changed, 35 insertions, 3 deletions
diff --git a/AUTHORS b/AUTHORS
index cee8ceb96e..5ef45ec7f2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -136,6 +136,7 @@ answer newbie questions, and generally made Django that much better:
btoll@bestweb.net
Jonathan Buchanan <jonathan.buchanan@gmail.com>
Jacob Burch <jacobburch@gmail.com>
+ Stephen Burrows <stephen.r.burrows@gmail.com>
Max Burstein <http://maxburstein.com>
Keith Bussell <kbussell@gmail.com>
C8E
diff --git a/django/forms/forms.py b/django/forms/forms.py
index 5362fd5aaf..2cfd4ec241 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
from collections import OrderedDict
import copy
+import datetime
import warnings
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
@@ -590,6 +591,11 @@ class BoundField(object):
data = self.form.initial.get(self.name, self.field.initial)
if callable(data):
data = data()
+ # If this is an auto-generated default date, nix the
+ # microseconds for standardized handling. See #22502.
+ if (isinstance(data, (datetime.datetime, datetime.time)) and
+ not getattr(self.field.widget, 'supports_microseconds', True)):
+ data = data.replace(microsecond=0)
else:
data = self.field.bound_data(
self.data, self.form.initial.get(self.name, self.field.initial)
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 53003749d3..27b056301d 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -429,6 +429,7 @@ class Textarea(Widget):
class DateTimeBaseInput(TextInput):
format_key = ''
+ supports_microseconds = False
def __init__(self, attrs=None, format=None):
super(DateTimeBaseInput, self).__init__(attrs)
@@ -863,6 +864,7 @@ class SplitDateTimeWidget(MultiWidget):
"""
A Widget that splits datetime input into two <input type="text"> boxes.
"""
+ supports_microseconds = False
def __init__(self, attrs=None, date_format=None, time_format=None):
widgets = (DateInput(attrs=attrs, format=date_format),
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index ea2858200c..a2ffc3b1fe 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -10,10 +10,10 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import RegexValidator
from django.forms import (
BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField,
- EmailField, FileField, FloatField, Form, forms, HiddenInput, IntegerField,
- MultipleChoiceField, MultipleHiddenInput, MultiValueField,
+ DateTimeField, EmailField, FileField, FloatField, Form, forms, HiddenInput,
+ IntegerField, MultipleChoiceField, MultipleHiddenInput, MultiValueField,
NullBooleanField, PasswordInput, RadioSelect, Select, SplitDateTimeField,
- Textarea, TextInput, ValidationError, widgets,
+ Textarea, TextInput, TimeField, ValidationError, widgets
)
from django.forms.utils import ErrorList
from django.http import QueryDict
@@ -1287,6 +1287,29 @@ class FormsTestCase(TestCase):
self.assertEqual(bound['password'].value(), 'foo')
self.assertEqual(unbound['password'].value(), None)
+ def test_initial_datetime_values(self):
+ now = datetime.datetime.now()
+ # Nix microseconds (since they should be ignored). #22502
+ now_no_ms = now.replace(microsecond=0)
+ if now == now_no_ms:
+ now = now.replace(microsecond=1)
+
+ def delayed_now():
+ return now
+
+ def delayed_now_time():
+ return now.time()
+
+ class DateTimeForm(Form):
+ auto_timestamp = DateTimeField(initial=delayed_now)
+ auto_time_only = TimeField(initial=delayed_now_time)
+ supports_microseconds = DateTimeField(initial=delayed_now, widget=TextInput)
+
+ unbound = DateTimeForm()
+ self.assertEqual(unbound['auto_timestamp'].value(), now_no_ms)
+ self.assertEqual(unbound['auto_time_only'].value(), now_no_ms.time())
+ self.assertEqual(unbound['supports_microseconds'].value(), now)
+
def test_help_text(self):
# You can specify descriptive text for a field by using the 'help_text' argument)
class UserRegistration(Form):