diff -r b758351d191f -r cc9b7e14412b web/lib/django/forms/widgets.py
--- a/web/lib/django/forms/widgets.py Wed May 19 17:43:59 2010 +0200
+++ b/web/lib/django/forms/widgets.py Tue May 25 02:43:45 2010 +0200
@@ -2,12 +2,7 @@
HTML Widget classes
"""
-try:
- set
-except NameError:
- from sets import Set as set # Python 2.3 fallback
-
-import copy
+import django.utils.copycompat as copy
from itertools import chain
from django.conf import settings
from django.utils.datastructures import MultiValueDict, MergeDict
@@ -15,8 +10,9 @@
from django.utils.translation import ugettext
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe
-from django.utils import datetime_safe
-from datetime import time
+from django.utils import formats
+import time
+import datetime
from util import flatatt
from urlparse import urljoin
@@ -46,7 +42,7 @@
# Any leftover attributes must be invalid.
# if media_attrs != {}:
- # raise TypeError, "'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys())
+ # raise TypeError("'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys()))
def __unicode__(self):
return self.render()
@@ -80,12 +76,16 @@
def add_js(self, data):
if data:
- self._js.extend([path for path in data if path not in self._js])
+ for path in data:
+ if path not in self._js:
+ self._js.append(path)
def add_css(self, data):
if data:
for medium, paths in data.items():
- self._css.setdefault(medium, []).extend([path for path in paths if path not in self._css[medium]])
+ for path in paths:
+ if not self._css.get(medium) or path not in self._css[medium]:
+ self._css.setdefault(medium, []).append(path)
def __add__(self, other):
combined = Media()
@@ -247,9 +247,16 @@
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
- return mark_safe(u'\n'.join([(u'' %
- flatatt(dict(value=force_unicode(v), **final_attrs)))
- for v in value]))
+ id_ = final_attrs.get('id', None)
+ inputs = []
+ for i, v in enumerate(value):
+ input_attrs = dict(value=force_unicode(v), **final_attrs)
+ if id_:
+ # An ID attribute was given. Add a numeric index as a suffix
+ # so that the inputs don't all have the same ID attribute.
+ input_attrs['id'] = '%s_%s' % (id_, i)
+ inputs.append(u'' % flatatt(input_attrs))
+ return mark_safe(u'\n'.join(inputs))
def value_from_datadict(self, data, files, name):
if isinstance(data, (MultiValueDict, MergeDict)):
@@ -288,7 +295,7 @@
class DateInput(Input):
input_type = 'text'
- format = '%Y-%m-%d' # '2006-10-25'
+ format = None
def __init__(self, attrs=None, format=None):
super(DateInput, self).__init__(attrs)
@@ -299,8 +306,7 @@
if value is None:
return ''
elif hasattr(value, 'strftime'):
- value = datetime_safe.new_date(value)
- return value.strftime(self.format)
+ return formats.localize_input(value, self.format)
return value
def render(self, name, value, attrs=None):
@@ -308,11 +314,19 @@
return super(DateInput, self).render(name, value, attrs)
def _has_changed(self, initial, data):
+ # If our field has show_hidden_initial=True, initial will be a string
+ # formatted by HiddenInput using formats.localize_input, which is not
+ # necessarily the format used for this widget. Attempt to convert it.
+ try:
+ input_format = formats.get_format('DATE_INPUT_FORMATS')[0]
+ initial = datetime.date(*time.strptime(initial, input_format)[:3])
+ except (TypeError, ValueError):
+ pass
return super(DateInput, self)._has_changed(self._format_value(initial), data)
class DateTimeInput(Input):
input_type = 'text'
- format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59'
+ format = None
def __init__(self, attrs=None, format=None):
super(DateTimeInput, self).__init__(attrs)
@@ -323,8 +337,7 @@
if value is None:
return ''
elif hasattr(value, 'strftime'):
- value = datetime_safe.new_datetime(value)
- return value.strftime(self.format)
+ return formats.localize_input(value, self.format)
return value
def render(self, name, value, attrs=None):
@@ -332,11 +345,19 @@
return super(DateTimeInput, self).render(name, value, attrs)
def _has_changed(self, initial, data):
+ # If our field has show_hidden_initial=True, initial will be a string
+ # formatted by HiddenInput using formats.localize_input, which is not
+ # necessarily the format used for this widget. Attempt to convert it.
+ try:
+ input_format = formats.get_format('DATETIME_INPUT_FORMATS')[0]
+ initial = datetime.datetime(*time.strptime(initial, input_format)[:6])
+ except (TypeError, ValueError):
+ pass
return super(DateTimeInput, self)._has_changed(self._format_value(initial), data)
class TimeInput(Input):
input_type = 'text'
- format = '%H:%M:%S' # '14:30:59'
+ format = None
def __init__(self, attrs=None, format=None):
super(TimeInput, self).__init__(attrs)
@@ -347,7 +368,7 @@
if value is None:
return ''
elif hasattr(value, 'strftime'):
- return value.strftime(self.format)
+ return formats.localize_input(value, self.format)
return value
def render(self, name, value, attrs=None):
@@ -355,6 +376,14 @@
return super(TimeInput, self).render(name, value, attrs)
def _has_changed(self, initial, data):
+ # If our field has show_hidden_initial=True, initial will be a string
+ # formatted by HiddenInput using formats.localize_input, which is not
+ # necessarily the format used for this widget. Attempt to convert it.
+ try:
+ input_format = formats.get_format('TIME_INPUT_FORMATS')[0]
+ initial = datetime.time(*time.strptime(initial, input_format)[3:6])
+ except (TypeError, ValueError):
+ pass
return super(TimeInput, self)._has_changed(self._format_value(initial), data)
class CheckboxInput(Widget):
@@ -382,7 +411,12 @@
# A missing value means False because HTML form submission does not
# send results for unselected checkboxes.
return False
- return super(CheckboxInput, self).value_from_datadict(data, files, name)
+ value = data.get(name)
+ # Translate true and false strings to boolean values.
+ values = {'true': True, 'false': False}
+ if isinstance(value, basestring):
+ value = values.get(value.lower(), value)
+ return value
def _has_changed(self, initial, data):
# Sometimes data or initial could be None or u'' which should be the
@@ -404,7 +438,7 @@
options = self.render_options(choices, [value])
if options:
output.append(options)
- output.append('')
+ output.append(u'')
return mark_safe(u'\n'.join(output))
def render_options(self, choices, selected_choices):
@@ -452,9 +486,13 @@
False: False}.get(value, None)
def _has_changed(self, initial, data):
- # Sometimes data or initial could be None or u'' which should be the
- # same thing as False.
- return bool(initial) != bool(data)
+ # For a NullBooleanSelect, None (unknown) and False (No)
+ # are not the same
+ if initial is not None:
+ initial = bool(initial)
+ if data is not None:
+ data = bool(data)
+ return initial != data
class SelectMultiple(Select):
def render(self, name, value, attrs=None, choices=()):
@@ -700,6 +738,11 @@
return media
media = property(_get_media)
+ def __deepcopy__(self, memo):
+ obj = super(MultiWidget, self).__deepcopy__(memo)
+ obj.widgets = copy.deepcopy(self.widgets)
+ return obj
+
class SplitDateTimeWidget(MultiWidget):
"""
A Widget that splits datetime input into two boxes.
@@ -725,6 +768,10 @@
"""
A Widget that splits datetime input into two inputs.
"""
- def __init__(self, attrs=None):
- widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs))
- super(SplitDateTimeWidget, self).__init__(widgets, attrs)
+ is_hidden = True
+
+ def __init__(self, attrs=None, date_format=None, time_format=None):
+ super(SplitHiddenDateTimeWidget, self).__init__(attrs, date_format, time_format)
+ for widget in self.widgets:
+ widget.input_type = 'hidden'
+ widget.is_hidden = True