Code

Ticket #8962: datetime-formatting-r8983.diff

File datetime-formatting-r8983.diff, 13.8 KB (added by mrmachine, 6 years ago)
Line 
1Index: django/forms/fields.py
2===================================================================
3--- django/forms/fields.py      (revision 8983)
4+++ django/forms/fields.py      (working copy)
5@@ -28,7 +28,7 @@
6 from django.utils.encoding import smart_unicode, smart_str
7 
8 from util import ErrorList, ValidationError
9-from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput, SplitHiddenDateTimeWidget
10+from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
11 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
12 
13 __all__ = (
14@@ -283,6 +283,7 @@
15 )
16 
17 class DateField(Field):
18+    widget = DateInput
19     default_error_messages = {
20         'invalid': _(u'Enter a valid date.'),
21     }
22@@ -843,19 +844,20 @@
23         self.widget.choices = self.choices
24 
25 class SplitDateTimeField(MultiValueField):
26+    widget = SplitDateTimeWidget
27     hidden_widget = SplitHiddenDateTimeWidget
28     default_error_messages = {
29         'invalid_date': _(u'Enter a valid date.'),
30         'invalid_time': _(u'Enter a valid time.'),
31     }
32 
33-    def __init__(self, *args, **kwargs):
34+    def __init__(self, input_date_formats=None, input_time_formats=None, *args, **kwargs):
35         errors = self.default_error_messages.copy()
36         if 'error_messages' in kwargs:
37             errors.update(kwargs['error_messages'])
38         fields = (
39-            DateField(error_messages={'invalid': errors['invalid_date']}),
40-            TimeField(error_messages={'invalid': errors['invalid_time']}),
41+            DateField(input_formats=input_date_formats, error_messages={'invalid': errors['invalid_date']}),
42+            TimeField(input_formats=input_time_formats, error_messages={'invalid': errors['invalid_time']}),
43         )
44         super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
45 
46Index: django/forms/widgets.py
47===================================================================
48--- django/forms/widgets.py     (revision 8983)
49+++ django/forms/widgets.py     (working copy)
50@@ -23,7 +23,7 @@
51 __all__ = (
52     'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput',
53     'HiddenInput', 'MultipleHiddenInput',
54-    'FileInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
55+    'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
56     'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
57     'CheckboxSelectMultiple', 'MultiWidget',
58     'SplitDateTimeWidget',
59@@ -286,6 +286,23 @@
60         return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
61                 conditional_escape(force_unicode(value))))
62 
63+class DateInput(Input):
64+    input_type = 'text'
65+    format = '%Y-%m-%d'     # '2006-10-25'
66+
67+    def __init__(self, attrs=None, format=None):
68+        super(DateInput, self).__init__(attrs)
69+        if format:
70+            self.format = format
71+
72+    def render(self, name, value, attrs=None):
73+        if value is None:
74+            value = ''
75+        elif hasattr(value, 'strftime'):
76+            value = datetime_safe.new_date(value)
77+            value = value.strftime(self.format)
78+        return super(DateInput, self).render(name, value, attrs)
79+
80 class DateTimeInput(Input):
81     input_type = 'text'
82     format = '%Y-%m-%d %H:%M:%S'     # '2006-10-25 14:30:59'
83@@ -305,12 +322,18 @@
84 
85 class TimeInput(Input):
86     input_type = 'text'
87+    format = '%H:%M:%S'     # '14:30:59'
88 
89+    def __init__(self, attrs=None, format=None):
90+        super(TimeInput, self).__init__(attrs)
91+        if format:
92+            self.format = format
93+
94     def render(self, name, value, attrs=None):
95         if value is None:
96             value = ''
97-        elif isinstance(value, time):
98-            value = value.replace(microsecond=0)
99+        elif hasattr(value, 'strftime'):
100+            value = value.strftime(self.format)
101         return super(TimeInput, self).render(name, value, attrs)
102 
103 class CheckboxInput(Widget):
104@@ -655,8 +678,9 @@
105     """
106     A Widget that splits datetime input into two <input type="text"> boxes.
107     """
108-    def __init__(self, attrs=None):
109-        widgets = (TextInput(attrs=attrs), TextInput(attrs=attrs))
110+    def __init__(self, attrs=None, date_format=None, time_format=None):
111+        widgets = (DateInput(attrs=attrs, format=date_format),
112+                   TimeInput(attrs=attrs, format=time_format))
113         super(SplitDateTimeWidget, self).__init__(widgets, attrs)
114 
115     def decompress(self, value):
116@@ -671,4 +695,3 @@
117     def __init__(self, attrs=None):
118         widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs))
119         super(SplitDateTimeWidget, self).__init__(widgets, attrs)
120-
121Index: django/contrib/localflavor/generic/forms.py
122===================================================================
123--- django/contrib/localflavor/generic/forms.py (revision 8983)
124+++ django/contrib/localflavor/generic/forms.py (working copy)
125@@ -36,3 +36,14 @@
126     def __init__(self, input_formats=None, *args, **kwargs):
127         input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
128         super(DateTimeField, self).__init__(input_formats=input_formats, *args, **kwargs)
129+
130+class SplitDateTimeField(forms.SplitDateTimeField):
131+    """
132+    Split date and time input fields which use non-US date and time input
133+    formats by default.
134+    """
135+    def __init__(self, input_date_formats=None, input_time_formats=None, *args, **kwargs):
136+        input_date_formats = input_date_formats or DEFAULT_DATE_INPUT_FORMATS
137+        input_time_formats = input_time_formats
138+        super(SplitDateTimeField, self).__init__(input_date_formats=input_date_formats,
139+                                                 input_time_formats=input_time_formats, *args, **kwargs)
140Index: tests/regressiontests/forms/widgets.py
141===================================================================
142--- tests/regressiontests/forms/widgets.py      (revision 8983)
143+++ tests/regressiontests/forms/widgets.py      (working copy)
144@@ -1071,6 +1071,11 @@
145 >>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
146 u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />'
147 
148+Or use 'date_format' and 'time_format' to change the way a value is displayed.
149+>>> w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M')
150+>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
151+u'<input type="text" name="date_0" value="10/01/2006" /><input type="text" name="date_1" value="07:30" />'
152+
153 >>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:40:00'])
154 False
155 >>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:41:00'])
156@@ -1093,6 +1098,34 @@
157 >>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
158 u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
159 
160+Or use 'format' to change the way a value is displayed.
161+>>> w = DateTimeInput(format='%d/%m/%Y %H:%M')
162+>>> w.render('date', d)
163+u'<input type="text" name="date" value="17/09/2007 12:51" />'
164+
165+# DateInput ###################################################################
166+
167+>>> w = DateInput()
168+>>> w.render('date', None)
169+u'<input type="text" name="date" />'
170+>>> d = datetime.date(2007, 9, 17)
171+>>> print d
172+2007-09-17
173+
174+>>> w.render('date', d)
175+u'<input type="text" name="date" value="2007-09-17" />'
176+>>> w.render('date', datetime.date(2007, 9, 17))
177+u'<input type="text" name="date" value="2007-09-17" />'
178+
179+We should be able to initialize from a unicode value.
180+>>> w.render('date', u'2007-09-17')
181+u'<input type="text" name="date" value="2007-09-17" />'
182+
183+Or use 'format' to change the way a value is displayed.
184+>>> w = DateInput(format='%d/%m/%Y')
185+>>> w.render('date', d)
186+u'<input type="text" name="date" value="17/09/2007" />'
187+
188 # TimeInput ###################################################################
189 
190 >>> w = TimeInput()
191@@ -1114,6 +1147,11 @@
192 >>> w.render('time', u'13:12:11')
193 u'<input type="text" name="time" value="13:12:11" />'
194 
195+Or use 'format' to change the way a value is displayed.
196+>>> w = TimeInput(format='%H:%M')
197+>>> w.render('time', t)
198+u'<input type="text" name="time" value="12:51" />'
199+
200 # SplitHiddenDateTimeWidget ###################################################
201 
202 >>> from django.forms.widgets import SplitHiddenDateTimeWidget
203@@ -1121,6 +1159,10 @@
204 >>> w = SplitHiddenDateTimeWidget()
205 >>> w.render('date', '')
206 u'<input type="hidden" name="date_0" /><input type="hidden" name="date_1" />'
207+>>> d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
208+>>> print d
209+2007-09-17 12:51:34.482548
210+
211 >>> w.render('date', d)
212 u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />'
213 >>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34))
214Index: docs/ref/contrib/localflavor.txt
215===================================================================
216--- docs/ref/contrib/localflavor.txt    (revision 8983)
217+++ docs/ref/contrib/localflavor.txt    (working copy)
218@@ -65,9 +65,9 @@
219     * `United States of America`_
220 
221 The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage,
222-containing useful code that is not specific to one particular country or
223-culture. Currently, it defines date and datetime input fields based on those
224-from :ref:`forms <topics-forms-index>`, but with non-US default formats.
225+containing useful code that is not specific to one particular country or culture.
226+Currently, it defines date, datetime and split datetime input fields based on
227+those from :ref:`forms <topics-forms-index>`, but with non-US default formats.
228 Here's an example of how to use them::
229 
230     from django import forms
231Index: docs/ref/forms/fields.txt
232===================================================================
233--- docs/ref/forms/fields.txt   (revision 8983)
234+++ docs/ref/forms/fields.txt   (working copy)
235@@ -396,7 +396,7 @@
236 
237 .. class:: DateField(**kwargs)
238 
239-    * Default widget: ``TextInput``
240+    * Default widget: ``DateInput``
241     * Empty value: ``None``
242     * Normalizes to: A Python ``datetime.date`` object.
243     * Validates that the given value is either a ``datetime.date``,
244@@ -418,6 +418,9 @@
245     '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
246     '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
247 
248+.. versionchanged:: development version
249+   The ``DateField`` used to use a ``TextInput`` widget by default. This has now changed.
250+
251 ``DateTimeField``
252 ~~~~~~~~~~~~~~~~~
253 
254@@ -737,6 +740,36 @@
255 
256 .. class:: SplitDateTimeField(**kwargs)
257 
258+    * Default widget: ``SplitDateTimeWidget``
259+    * Empty value: ``None``
260+    * Normalizes to: A Python ``datetime.datetime`` object.
261+    * Validates that the given value is either a ``datetime.datetime``,
262+      ``datetime.date`` or string formatted in a particular datetime format.
263+    * Error message keys: ``required``, ``invalid``
264+
265+Takes two optional arguments:
266+
267+.. attribute:: SplitDateTimeField.input_date_formats
268+
269+A list of formats used to attempt to convert a string to a valid
270+``datetime.date`` object.
271+
272+If no ``input_date_formats`` argument is provided, the default input formats
273+for ``DateField`` are used.
274+
275+.. attribute:: SplitDateTimeField.input_time_formats
276+
277+A list of formats used to attempt to convert a string to a valid
278+``datetime.time`` object.
279+
280+If no ``input_time_formats`` argument is provided, the default input formats
281+for ``TimeField`` are used.
282+
283+.. versionchanged:: development version
284+   The ``SplitDateTimeField`` used to use two ``TextInput`` widgets by default.
285+   The ``input_date_formats`` and ``input_time_formats`` arguments are also
286+   new in the development version.
287+
288 Fields which handle relationships
289 ---------------------------------
290 
291Index: docs/ref/forms/widgets.txt
292===================================================================
293--- docs/ref/forms/widgets.txt  (revision 8983)
294+++ docs/ref/forms/widgets.txt  (working copy)
295@@ -36,12 +36,49 @@
296 
297     File upload input: ``<input type='file' ...>``
298 
299+.. class:: DateInput
300+
301+    .. versionadded:: development version
302+
303+    Date input as a simple text box: ``<input type='text' ...>``
304+
305+    Takes one optional argument:
306+   
307+    .. attribute:: DateInput.format
308+
309+        The format in which this field's initial value will be displayed.
310+
311+    If no ``format`` argument is provided, the default format is ``'%Y-%m-%d'``.
312+
313 .. class:: DateTimeInput
314 
315     .. versionadded:: 1.0
316 
317     Date/time input as a simple text box: ``<input type='text' ...>``
318 
319+    Takes one optional argument:
320+   
321+    .. attribute:: DateTimeInput.format
322+   
323+        The format in which this field's initial value will be displayed.
324+   
325+    If no ``format`` argument is provided, the default format is ``'%Y-%m-%d %H:%M:%S'``.
326+
327+.. class:: TimeInput
328+
329+    Time input as a simple text box: ``<input type='text' ...>``
330+
331+    Takes one optional argument:
332+   
333+    .. attribute:: TimeInput.format
334+   
335+        The format in which this field's initial value will be displayed.
336+   
337+    If no ``format`` argument is provided, the default format is ``'%H:%M:%S'``.
338+
339+    .. versionchanged:: development version
340+       The ``format`` argument is new in the development version.
341+
342 .. class:: Textarea
343 
344     Text area: ``<textarea>...</textarea>``
345@@ -91,9 +128,12 @@
346 
347 .. class:: SplitDateTimeWidget
348 
349-    Wrapper around two ``TextInput`` widgets: one for the date, and one for the
350-    time.
351+    Wrapper around two widgets: ``DateInput`` for the date, and ``TimeInput``
352+    for the time.
353 
354+    Takes two optional arguments, ``date_format`` and ``time_format``, which
355+    work just like the ``format`` argument for ``DateInput`` and ``TimeInput``.
356+
357 Specifying widgets
358 ------------------
359