summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2021-07-13 22:15:13 -0400
committerCarlton Gibson <carlton.gibson@noumenal.es>2021-07-16 15:51:20 +0200
commit0dc25526d8daaaa59968d4b1b597968e197f040c (patch)
treebde70ecd2cf8000c08553274903ac42bad86bd00
parent788441c6ab4e0167aadc155a4362a87694e38aa5 (diff)
downloaddjango-0dc25526d8daaaa59968d4b1b597968e197f040c.tar.gz
Fixed #32924 -- Changed BaseForm.get_initial_for_field() to remove microseconds when needed.
-rw-r--r--django/forms/boundfield.py9
-rw-r--r--django/forms/forms.py6
-rw-r--r--tests/forms_tests/tests/test_forms.py14
3 files changed, 21 insertions, 8 deletions
diff --git a/django/forms/boundfield.py b/django/forms/boundfield.py
index 54f9e9a64f..2ff8b0ee26 100644
--- a/django/forms/boundfield.py
+++ b/django/forms/boundfield.py
@@ -1,4 +1,3 @@
-import datetime
import re
from django.core.exceptions import ValidationError
@@ -228,13 +227,7 @@ class BoundField:
@cached_property
def initial(self):
- data = self.form.get_initial_for_field(self.field, self.name)
- # 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 self.field.widget.supports_microseconds):
- data = data.replace(microsecond=0)
- return data
+ return self.form.get_initial_for_field(self.field, self.name)
def build_widget_attrs(self, attrs, widget=None):
widget = widget or self.field.widget
diff --git a/django/forms/forms.py b/django/forms/forms.py
index ac6ef667d9..2bf268ae76 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -3,6 +3,7 @@ Form classes
"""
import copy
+import datetime
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms.fields import Field, FileField
@@ -475,6 +476,11 @@ class BaseForm:
value = self.initial.get(field_name, field.initial)
if callable(value):
value = value()
+ # If this is an auto-generated default date, nix the microseconds
+ # for standardized handling. See #22502.
+ if (isinstance(value, (datetime.datetime, datetime.time)) and
+ not field.widget.supports_microseconds):
+ value = value.replace(microsecond=0)
return value
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index b4fb5737af..f3ee64ceda 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -1983,11 +1983,15 @@ Password: <input type="password" name="password" required></li>
)
def test_get_initial_for_field(self):
+ now = datetime.datetime(2006, 10, 25, 14, 30, 45, 123456)
+
class PersonForm(Form):
first_name = CharField(initial='John')
last_name = CharField(initial='Doe')
age = IntegerField()
occupation = CharField(initial=lambda: 'Unknown')
+ dt_fixed = DateTimeField(initial=now)
+ dt_callable = DateTimeField(initial=lambda: now)
form = PersonForm(initial={'first_name': 'Jane'})
cases = [
@@ -1997,6 +2001,9 @@ Password: <input type="password" name="password" required></li>
('first_name', 'Jane'),
# Callables are evaluated.
('occupation', 'Unknown'),
+ # Microseconds are removed from datetimes.
+ ('dt_fixed', datetime.datetime(2006, 10, 25, 14, 30, 45)),
+ ('dt_callable', datetime.datetime(2006, 10, 25, 14, 30, 45)),
]
for field_name, expected in cases:
with self.subTest(field_name=field_name):
@@ -2104,6 +2111,8 @@ Password: <input type="password" name="password" required></li>
supports_microseconds = False
class DateTimeForm(Form):
+ # Test a non-callable.
+ fixed = DateTimeField(initial=now)
auto_timestamp = DateTimeField(initial=delayed_now)
auto_time_only = TimeField(initial=delayed_now_time)
supports_microseconds = DateTimeField(initial=delayed_now, widget=TextInput)
@@ -2113,6 +2122,7 @@ Password: <input type="password" name="password" required></li>
unbound = DateTimeForm()
cases = [
+ ('fixed', now_no_ms),
('auto_timestamp', now_no_ms),
('auto_time_only', now_no_ms.time()),
('supports_microseconds', now),
@@ -2124,6 +2134,10 @@ Password: <input type="password" name="password" required></li>
with self.subTest(field_name=field_name):
actual = unbound[field_name].value()
self.assertEqual(actual, expected)
+ # Also check get_initial_for_field().
+ field = unbound.fields[field_name]
+ actual = unbound.get_initial_for_field(field, field_name)
+ self.assertEqual(actual, expected)
def get_datetime_form_with_callable_initial(self, disabled, microseconds=0):
class FakeTime: