Fixed #13560 -- Fixed localization of widgets.
Particularly this fixes the SplitDateTimeField and the AdminDateWidget by localizating the widget's value in its render method instead of the form field. Thanks to David Danier for the report and Russell for help with the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@13296 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8a6cb3d969
commit
b057a8b247
|
@ -44,7 +44,7 @@ class FilteredSelectMultiple(forms.SelectMultiple):
|
||||||
(name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
|
(name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
|
||||||
return mark_safe(u''.join(output))
|
return mark_safe(u''.join(output))
|
||||||
|
|
||||||
class AdminDateWidget(forms.DateTimeInput):
|
class AdminDateWidget(forms.DateInput):
|
||||||
class Media:
|
class Media:
|
||||||
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
|
||||||
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
|
||||||
|
|
|
@ -105,6 +105,8 @@ class Field(object):
|
||||||
|
|
||||||
# Trigger the localization machinery if needed.
|
# Trigger the localization machinery if needed.
|
||||||
self.localize = localize
|
self.localize = localize
|
||||||
|
if self.localize:
|
||||||
|
widget.is_localized = True
|
||||||
|
|
||||||
# Hook into self.widget_attrs() for any Field-specific HTML attributes.
|
# Hook into self.widget_attrs() for any Field-specific HTML attributes.
|
||||||
extra_attrs = self.widget_attrs(widget)
|
extra_attrs = self.widget_attrs(widget)
|
||||||
|
@ -125,9 +127,6 @@ class Field(object):
|
||||||
|
|
||||||
self.validators = self.default_validators + validators
|
self.validators = self.default_validators + validators
|
||||||
|
|
||||||
def localize_value(self, value):
|
|
||||||
return formats.localize_input(value)
|
|
||||||
|
|
||||||
def to_python(self, value):
|
def to_python(self, value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -843,9 +842,14 @@ class SplitDateTimeField(MultiValueField):
|
||||||
errors = self.default_error_messages.copy()
|
errors = self.default_error_messages.copy()
|
||||||
if 'error_messages' in kwargs:
|
if 'error_messages' in kwargs:
|
||||||
errors.update(kwargs['error_messages'])
|
errors.update(kwargs['error_messages'])
|
||||||
|
localize = kwargs.get('localize', False)
|
||||||
fields = (
|
fields = (
|
||||||
DateField(input_formats=input_date_formats, error_messages={'invalid': errors['invalid_date']}),
|
DateField(input_formats=input_date_formats,
|
||||||
TimeField(input_formats=input_time_formats, error_messages={'invalid': errors['invalid_time']}),
|
error_messages={'invalid': errors['invalid_date']},
|
||||||
|
localize=localize),
|
||||||
|
TimeField(input_formats=input_time_formats,
|
||||||
|
error_messages={'invalid': errors['invalid_time']},
|
||||||
|
localize=localize),
|
||||||
)
|
)
|
||||||
super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
|
super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -443,8 +443,6 @@ class BoundField(StrAndUnicode):
|
||||||
name = self.html_name
|
name = self.html_name
|
||||||
else:
|
else:
|
||||||
name = self.html_initial_name
|
name = self.html_initial_name
|
||||||
if self.field.localize:
|
|
||||||
data = self.field.localize_value(data)
|
|
||||||
return widget.render(name, data, attrs=attrs)
|
return widget.render(name, data, attrs=attrs)
|
||||||
|
|
||||||
def as_text(self, attrs=None, **kwargs):
|
def as_text(self, attrs=None, **kwargs):
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.utils.html import escape, conditional_escape
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.utils.encoding import StrAndUnicode, force_unicode
|
from django.utils.encoding import StrAndUnicode, force_unicode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils import formats
|
from django.utils import datetime_safe, formats
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
from util import flatatt
|
from util import flatatt
|
||||||
|
@ -133,6 +133,7 @@ class Widget(object):
|
||||||
__metaclass__ = MediaDefiningClass
|
__metaclass__ = MediaDefiningClass
|
||||||
is_hidden = False # Determines whether this corresponds to an <input type="hidden">.
|
is_hidden = False # Determines whether this corresponds to an <input type="hidden">.
|
||||||
needs_multipart_form = False # Determines does this widget need multipart-encrypted form
|
needs_multipart_form = False # Determines does this widget need multipart-encrypted form
|
||||||
|
is_localized = False
|
||||||
|
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
if attrs is not None:
|
if attrs is not None:
|
||||||
|
@ -208,12 +209,18 @@ class Input(Widget):
|
||||||
"""
|
"""
|
||||||
input_type = None # Subclasses must define this.
|
input_type = None # Subclasses must define this.
|
||||||
|
|
||||||
|
def _format_value(self, value):
|
||||||
|
if self.is_localized:
|
||||||
|
return formats.localize_input(value)
|
||||||
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
if value is None: value = ''
|
if value is None:
|
||||||
|
value = ''
|
||||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||||
if value != '':
|
if value != '':
|
||||||
# Only add the 'value' attribute if a value is non-empty.
|
# Only add the 'value' attribute if a value is non-empty.
|
||||||
final_attrs['value'] = force_unicode(value)
|
final_attrs['value'] = force_unicode(self._format_value(value))
|
||||||
return mark_safe(u'<input%s />' % flatatt(final_attrs))
|
return mark_safe(u'<input%s />' % flatatt(final_attrs))
|
||||||
|
|
||||||
class TextInput(Input):
|
class TextInput(Input):
|
||||||
|
@ -295,7 +302,7 @@ class Textarea(Widget):
|
||||||
|
|
||||||
class DateInput(Input):
|
class DateInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = None
|
format = '%Y-%m-%d' # '2006-10-25'
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(DateInput, self).__init__(attrs)
|
super(DateInput, self).__init__(attrs)
|
||||||
|
@ -303,16 +310,13 @@ class DateInput(Input):
|
||||||
self.format = format
|
self.format = format
|
||||||
|
|
||||||
def _format_value(self, value):
|
def _format_value(self, value):
|
||||||
if value is None:
|
if self.is_localized:
|
||||||
return ''
|
return formats.localize_input(value)
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
return formats.localize_input(value, self.format)
|
value = datetime_safe.new_date(value)
|
||||||
|
return value.strftime(self.format)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
value = self._format_value(value)
|
|
||||||
return super(DateInput, self).render(name, value, attrs)
|
|
||||||
|
|
||||||
def _has_changed(self, initial, data):
|
def _has_changed(self, initial, data):
|
||||||
# If our field has show_hidden_initial=True, initial will be a string
|
# If our field has show_hidden_initial=True, initial will be a string
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
|
@ -326,7 +330,7 @@ class DateInput(Input):
|
||||||
|
|
||||||
class DateTimeInput(Input):
|
class DateTimeInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = None
|
format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59'
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(DateTimeInput, self).__init__(attrs)
|
super(DateTimeInput, self).__init__(attrs)
|
||||||
|
@ -334,16 +338,13 @@ class DateTimeInput(Input):
|
||||||
self.format = format
|
self.format = format
|
||||||
|
|
||||||
def _format_value(self, value):
|
def _format_value(self, value):
|
||||||
if value is None:
|
if self.is_localized:
|
||||||
return ''
|
return formats.localize_input(value)
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
return formats.localize_input(value, self.format)
|
value = datetime_safe.new_datetime(value)
|
||||||
|
return value.strftime(self.format)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
value = self._format_value(value)
|
|
||||||
return super(DateTimeInput, self).render(name, value, attrs)
|
|
||||||
|
|
||||||
def _has_changed(self, initial, data):
|
def _has_changed(self, initial, data):
|
||||||
# If our field has show_hidden_initial=True, initial will be a string
|
# If our field has show_hidden_initial=True, initial will be a string
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
|
@ -357,7 +358,7 @@ class DateTimeInput(Input):
|
||||||
|
|
||||||
class TimeInput(Input):
|
class TimeInput(Input):
|
||||||
input_type = 'text'
|
input_type = 'text'
|
||||||
format = None
|
format = '%H:%M:%S' # '14:30:59'
|
||||||
|
|
||||||
def __init__(self, attrs=None, format=None):
|
def __init__(self, attrs=None, format=None):
|
||||||
super(TimeInput, self).__init__(attrs)
|
super(TimeInput, self).__init__(attrs)
|
||||||
|
@ -365,16 +366,12 @@ class TimeInput(Input):
|
||||||
self.format = format
|
self.format = format
|
||||||
|
|
||||||
def _format_value(self, value):
|
def _format_value(self, value):
|
||||||
if value is None:
|
if self.is_localized:
|
||||||
return ''
|
return formats.localize_input(value)
|
||||||
elif hasattr(value, 'strftime'):
|
elif hasattr(value, 'strftime'):
|
||||||
return formats.localize_input(value, self.format)
|
return value.strftime(self.format)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
value = self._format_value(value)
|
|
||||||
return super(TimeInput, self).render(name, value, attrs)
|
|
||||||
|
|
||||||
def _has_changed(self, initial, data):
|
def _has_changed(self, initial, data):
|
||||||
# If our field has show_hidden_initial=True, initial will be a string
|
# If our field has show_hidden_initial=True, initial will be a string
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
|
@ -674,6 +671,9 @@ class MultiWidget(Widget):
|
||||||
super(MultiWidget, self).__init__(attrs)
|
super(MultiWidget, self).__init__(attrs)
|
||||||
|
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
|
if self.is_localized:
|
||||||
|
for widget in self.widgets:
|
||||||
|
widget.is_localized = self.is_localized
|
||||||
# value is a list of values, each corresponding to a widget
|
# value is a list of values, each corresponding to a widget
|
||||||
# in self.widgets.
|
# in self.widgets.
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
|
|
|
@ -105,6 +105,7 @@ HTML escaped.
|
||||||
<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
<p class="datetime">Date: <input value="2007-12-01" type="text" class="vDateField" name="test_0" size="10" /><br />Time: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
||||||
>>> activate('de-at')
|
>>> activate('de-at')
|
||||||
>>> settings.USE_L10N = True
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.is_localized = True
|
||||||
>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
|
>>> print conditional_escape(w.render('test', datetime(2007, 12, 1, 9, 30)))
|
||||||
<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>
|
||||||
>>> deactivate()
|
>>> deactivate()
|
||||||
|
|
|
@ -1135,6 +1135,7 @@ u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
|
||||||
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
|
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
|
||||||
>>> activate('de-at')
|
>>> activate('de-at')
|
||||||
>>> settings.USE_L10N = True
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.is_localized = True
|
||||||
>>> w.render('date', d)
|
>>> w.render('date', d)
|
||||||
u'<input type="text" name="date" value="17.09.2007 12:51:34" />'
|
u'<input type="text" name="date" value="17.09.2007 12:51:34" />'
|
||||||
>>> deactivate()
|
>>> deactivate()
|
||||||
|
@ -1176,6 +1177,7 @@ u'<input type="text" name="date" value="2007-09-17" />'
|
||||||
|
|
||||||
>>> activate('de-at')
|
>>> activate('de-at')
|
||||||
>>> settings.USE_L10N = True
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.is_localized = True
|
||||||
>>> w.render('date', d)
|
>>> w.render('date', d)
|
||||||
u'<input type="text" name="date" value="17.09.2007" />'
|
u'<input type="text" name="date" value="17.09.2007" />'
|
||||||
>>> deactivate()
|
>>> deactivate()
|
||||||
|
@ -1220,6 +1222,7 @@ u'<input type="text" name="time" value="13:12:11" />'
|
||||||
|
|
||||||
>>> activate('de-at')
|
>>> activate('de-at')
|
||||||
>>> settings.USE_L10N = True
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.is_localized = True
|
||||||
>>> w.render('date', d)
|
>>> w.render('date', d)
|
||||||
u'<input type="text" name="date" value="17.09.2007" />'
|
u'<input type="text" name="date" value="17.09.2007" />'
|
||||||
>>> deactivate()
|
>>> deactivate()
|
||||||
|
@ -1259,6 +1262,7 @@ u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" n
|
||||||
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />'
|
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />'
|
||||||
>>> activate('de-at')
|
>>> activate('de-at')
|
||||||
>>> settings.USE_L10N = True
|
>>> settings.USE_L10N = True
|
||||||
|
>>> w.is_localized = True
|
||||||
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
|
||||||
u'<input type="hidden" name="date_0" value="17.09.2007" /><input type="hidden" name="date_1" value="12:51:00" />'
|
u'<input type="hidden" name="date_0" value="17.09.2007" /><input type="hidden" name="date_1" value="12:51:00" />'
|
||||||
>>> deactivate()
|
>>> deactivate()
|
||||||
|
|
|
@ -16,6 +16,7 @@ class SelectDateForm(forms.Form):
|
||||||
class CompanyForm(forms.ModelForm):
|
class CompanyForm(forms.ModelForm):
|
||||||
cents_payed = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
|
cents_payed = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
|
||||||
products_delivered = forms.IntegerField(localize=True)
|
products_delivered = forms.IntegerField(localize=True)
|
||||||
|
date_added = forms.DateTimeField(localize=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Company
|
model = Company
|
||||||
|
|
Loading…
Reference in New Issue