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

[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 a5de0df5 from master.
parent 8a090c21
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+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
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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),
+26 −3
Original line number Diff line number Diff line
@@ -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):