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.
This commit is contained in:
parent
35e1b1efab
commit
a5de0df58b
1
AUTHORS
1
AUTHORS
|
@ -137,6 +137,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
btoll@bestweb.net
|
btoll@bestweb.net
|
||||||
Jonathan Buchanan <jonathan.buchanan@gmail.com>
|
Jonathan Buchanan <jonathan.buchanan@gmail.com>
|
||||||
Jacob Burch <jacobburch@gmail.com>
|
Jacob Burch <jacobburch@gmail.com>
|
||||||
|
Stephen Burrows <stephen.r.burrows@gmail.com>
|
||||||
Max Burstein <http://maxburstein.com>
|
Max Burstein <http://maxburstein.com>
|
||||||
Keith Bussell <kbussell@gmail.com>
|
Keith Bussell <kbussell@gmail.com>
|
||||||
C8E
|
C8E
|
||||||
|
|
|
@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import copy
|
import copy
|
||||||
|
import datetime
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
|
||||||
|
@ -593,6 +594,11 @@ class BoundField(object):
|
||||||
data = self.form.initial.get(self.name, self.field.initial)
|
data = self.form.initial.get(self.name, self.field.initial)
|
||||||
if callable(data):
|
if callable(data):
|
||||||
data = 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:
|
else:
|
||||||
data = self.field.bound_data(
|
data = self.field.bound_data(
|
||||||
self.data, self.form.initial.get(self.name, self.field.initial)
|
self.data, self.form.initial.get(self.name, self.field.initial)
|
||||||
|
|
|
@ -419,6 +419,7 @@ class Textarea(Widget):
|
||||||
|
|
||||||
class DateTimeBaseInput(TextInput):
|
class DateTimeBaseInput(TextInput):
|
||||||
format_key = ''
|
format_key = ''
|
||||||
|
supports_microseconds = False
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(DateTimeBaseInput, self).__init__(attrs)
|
super(DateTimeBaseInput, self).__init__(attrs)
|
||||||
|
@ -846,6 +847,7 @@ class SplitDateTimeWidget(MultiWidget):
|
||||||
"""
|
"""
|
||||||
A Widget that splits datetime input into two <input type="text"> boxes.
|
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):
|
def __init__(self, attrs=None, date_format=None, time_format=None):
|
||||||
widgets = (DateInput(attrs=attrs, format=date_format),
|
widgets = (DateInput(attrs=attrs, format=date_format),
|
||||||
|
|
|
@ -11,10 +11,10 @@ from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.core.validators import RegexValidator
|
from django.core.validators import RegexValidator
|
||||||
from django.forms import (
|
from django.forms import (
|
||||||
BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField,
|
BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField,
|
||||||
EmailField, FileField, FloatField, Form, forms, HiddenInput, IntegerField,
|
DateTimeField, EmailField, FileField, FloatField, Form, forms, HiddenInput,
|
||||||
MultipleChoiceField, MultipleHiddenInput, MultiValueField,
|
IntegerField, MultipleChoiceField, MultipleHiddenInput, MultiValueField,
|
||||||
NullBooleanField, PasswordInput, RadioSelect, Select, SplitDateTimeField,
|
NullBooleanField, PasswordInput, RadioSelect, Select, SplitDateTimeField,
|
||||||
Textarea, TextInput, ValidationError, widgets,
|
Textarea, TextInput, TimeField, ValidationError, widgets
|
||||||
)
|
)
|
||||||
from django.forms.utils import ErrorList
|
from django.forms.utils import ErrorList
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
|
@ -1321,6 +1321,29 @@ class FormsTestCase(TestCase):
|
||||||
self.assertEqual(bound['password'].value(), 'foo')
|
self.assertEqual(bound['password'].value(), 'foo')
|
||||||
self.assertEqual(unbound['password'].value(), None)
|
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):
|
def test_help_text(self):
|
||||||
# You can specify descriptive text for a field by using the 'help_text' argument)
|
# You can specify descriptive text for a field by using the 'help_text' argument)
|
||||||
class UserRegistration(Form):
|
class UserRegistration(Form):
|
||||||
|
|
Loading…
Reference in New Issue