mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						 Claude Paroz
						Claude Paroz
					
				
			
			
				
	
			
			
			
						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): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user