Commit a5de0df5 authored by Stephen Burrows's avatar Stephen Burrows Committed by Claude Paroz
Browse files

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.
parent 35e1b1ef
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -137,6 +137,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
+6 −0
Original line number Diff line number Diff line
@@ -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
@@ -593,6 +594,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)
+2 −0
Original line number Diff line number Diff line
@@ -419,6 +419,7 @@ class Textarea(Widget):

class DateTimeBaseInput(TextInput):
    format_key = ''
    supports_microseconds = False

    def __init__(self, attrs=None, format=None):
        super(DateTimeBaseInput, self).__init__(attrs)
@@ -846,6 +847,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),
+26 −3
Original line number Diff line number Diff line
@@ -11,10 +11,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
@@ -1321,6 +1321,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):