mirror of https://github.com/django/django.git
Fixed #13032 - Added localize parameter to form fields to be able to selectively enable localization.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12867 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ad5afd6ed2
commit
ca4c6f65ea
|
@ -71,7 +71,7 @@ class Field(object):
|
||||||
|
|
||||||
def __init__(self, required=True, widget=None, label=None, initial=None,
|
def __init__(self, required=True, widget=None, label=None, initial=None,
|
||||||
help_text=None, error_messages=None, show_hidden_initial=False,
|
help_text=None, error_messages=None, show_hidden_initial=False,
|
||||||
validators=[]):
|
validators=[], localize=False):
|
||||||
# required -- Boolean that specifies whether the field is required.
|
# required -- Boolean that specifies whether the field is required.
|
||||||
# True by default.
|
# True by default.
|
||||||
# widget -- A Widget class, or instance of a Widget class, that should
|
# widget -- A Widget class, or instance of a Widget class, that should
|
||||||
|
@ -85,9 +85,12 @@ class Field(object):
|
||||||
# initial -- A value to use in this Field's initial display. This value
|
# initial -- A value to use in this Field's initial display. This value
|
||||||
# is *not* used as a fallback if data isn't given.
|
# is *not* used as a fallback if data isn't given.
|
||||||
# help_text -- An optional string to use as "help text" for this Field.
|
# help_text -- An optional string to use as "help text" for this Field.
|
||||||
|
# error_messages -- An optional dictionary to override the default
|
||||||
|
# messages that the field will raise.
|
||||||
# show_hidden_initial -- Boolean that specifies if it is needed to render a
|
# show_hidden_initial -- Boolean that specifies if it is needed to render a
|
||||||
# hidden widget with initial value after widget.
|
# hidden widget with initial value after widget.
|
||||||
# validators -- List of addtional validators to use
|
# validators -- List of addtional validators to use
|
||||||
|
# localize -- Boolean that specifies if the field should be localized.
|
||||||
if label is not None:
|
if label is not None:
|
||||||
label = smart_unicode(label)
|
label = smart_unicode(label)
|
||||||
self.required, self.label, self.initial = required, label, initial
|
self.required, self.label, self.initial = required, label, initial
|
||||||
|
@ -100,6 +103,9 @@ class Field(object):
|
||||||
if isinstance(widget, type):
|
if isinstance(widget, type):
|
||||||
widget = widget()
|
widget = widget()
|
||||||
|
|
||||||
|
# Trigger the localization machinery if needed.
|
||||||
|
self.localize = localize
|
||||||
|
|
||||||
# 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)
|
||||||
if extra_attrs:
|
if extra_attrs:
|
||||||
|
@ -119,6 +125,9 @@ 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
|
||||||
|
|
||||||
|
@ -213,7 +222,8 @@ class IntegerField(Field):
|
||||||
value = super(IntegerField, self).to_python(value)
|
value = super(IntegerField, self).to_python(value)
|
||||||
if value in validators.EMPTY_VALUES:
|
if value in validators.EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = formats.sanitize_separators(value)
|
if self.localize:
|
||||||
|
value = formats.sanitize_separators(value)
|
||||||
try:
|
try:
|
||||||
value = int(str(value))
|
value = int(str(value))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
|
@ -233,7 +243,8 @@ class FloatField(IntegerField):
|
||||||
value = super(IntegerField, self).to_python(value)
|
value = super(IntegerField, self).to_python(value)
|
||||||
if value in validators.EMPTY_VALUES:
|
if value in validators.EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = formats.sanitize_separators(value)
|
if self.localize:
|
||||||
|
value = formats.sanitize_separators(value)
|
||||||
try:
|
try:
|
||||||
value = float(value)
|
value = float(value)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
|
@ -268,7 +279,8 @@ class DecimalField(Field):
|
||||||
"""
|
"""
|
||||||
if value in validators.EMPTY_VALUES:
|
if value in validators.EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = formats.sanitize_separators(value)
|
if self.localize:
|
||||||
|
value = formats.sanitize_separators(value)
|
||||||
value = smart_str(value).strip()
|
value = smart_str(value).strip()
|
||||||
try:
|
try:
|
||||||
value = Decimal(value)
|
value = Decimal(value)
|
||||||
|
|
|
@ -443,6 +443,8 @@ 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):
|
||||||
|
|
|
@ -13,7 +13,6 @@ from django.utils.safestring import mark_safe
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
from django.utils.formats import get_format
|
|
||||||
from util import flatatt
|
from util import flatatt
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
|
||||||
|
@ -214,7 +213,7 @@ class Input(Widget):
|
||||||
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(formats.localize_input(value))
|
final_attrs['value'] = force_unicode(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):
|
||||||
|
@ -319,7 +318,7 @@ class DateInput(Input):
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
# necessarily the format used for this widget. Attempt to convert it.
|
# necessarily the format used for this widget. Attempt to convert it.
|
||||||
try:
|
try:
|
||||||
input_format = get_format('DATE_INPUT_FORMATS')[0]
|
input_format = formats.get_format('DATE_INPUT_FORMATS')[0]
|
||||||
initial = datetime.date(*time.strptime(initial, input_format)[:3])
|
initial = datetime.date(*time.strptime(initial, input_format)[:3])
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
pass
|
pass
|
||||||
|
@ -350,7 +349,7 @@ class DateTimeInput(Input):
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
# necessarily the format used for this widget. Attempt to convert it.
|
# necessarily the format used for this widget. Attempt to convert it.
|
||||||
try:
|
try:
|
||||||
input_format = get_format('DATETIME_INPUT_FORMATS')[0]
|
input_format = formats.get_format('DATETIME_INPUT_FORMATS')[0]
|
||||||
initial = datetime.datetime(*time.strptime(initial, input_format)[:6])
|
initial = datetime.datetime(*time.strptime(initial, input_format)[:6])
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
pass
|
pass
|
||||||
|
@ -381,7 +380,7 @@ class TimeInput(Input):
|
||||||
# formatted by HiddenInput using formats.localize_input, which is not
|
# formatted by HiddenInput using formats.localize_input, which is not
|
||||||
# necessarily the format used for this widget. Attempt to convert it.
|
# necessarily the format used for this widget. Attempt to convert it.
|
||||||
try:
|
try:
|
||||||
input_format = get_format('TIME_INPUT_FORMATS')[0]
|
input_format = formats.get_format('TIME_INPUT_FORMATS')[0]
|
||||||
initial = datetime.time(*time.strptime(initial, input_format)[3:6])
|
initial = datetime.time(*time.strptime(initial, input_format)[3:6])
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
pass
|
pass
|
||||||
|
@ -771,6 +770,8 @@ class SplitHiddenDateTimeWidget(SplitDateTimeWidget):
|
||||||
"""
|
"""
|
||||||
is_hidden = True
|
is_hidden = True
|
||||||
|
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None, date_format=None, time_format=None):
|
||||||
widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs))
|
super(SplitHiddenDateTimeWidget, self).__init__(attrs, date_format, time_format)
|
||||||
super(SplitDateTimeWidget, self).__init__(widgets, attrs)
|
for widget in self.widgets:
|
||||||
|
widget.input_type = 'hidden'
|
||||||
|
widget.is_hidden = True
|
||||||
|
|
|
@ -259,6 +259,7 @@ error message keys it uses.
|
||||||
|
|
||||||
``validators``
|
``validators``
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.2
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
.. attribute:: Field.validators
|
.. attribute:: Field.validators
|
||||||
|
@ -268,6 +269,20 @@ for this field.
|
||||||
|
|
||||||
See the :ref:`validators documentation <ref-validators>` for more information.
|
See the :ref:`validators documentation <ref-validators>` for more information.
|
||||||
|
|
||||||
|
``localize``
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. versionadded:: 1.2
|
||||||
|
|
||||||
|
.. attribute:: Field.localize
|
||||||
|
|
||||||
|
The ``localize`` argument enables the localization of form data, input as well
|
||||||
|
as the rendered output.
|
||||||
|
|
||||||
|
See the :ref:`format localization <format-localization>` documentation for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
|
||||||
Built-in ``Field`` classes
|
Built-in ``Field`` classes
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,13 @@ Django uses different formats for different locales when guessing the format
|
||||||
used by the user when inputting data on forms. Note that Django uses different
|
used by the user when inputting data on forms. Note that Django uses different
|
||||||
formats for displaying data, and for parsing it.
|
formats for displaying data, and for parsing it.
|
||||||
|
|
||||||
|
To enable a form field to localize input and output data simply use its
|
||||||
|
``localize`` argument::
|
||||||
|
|
||||||
|
class CashRegisterForm(forms.Form):
|
||||||
|
product = forms.CharField()
|
||||||
|
revenue = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
|
||||||
|
|
||||||
Creating custom format files
|
Creating custom format files
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,19 @@ from django.forms.extras import SelectDateWidget
|
||||||
from models import Company
|
from models import Company
|
||||||
|
|
||||||
class I18nForm(forms.Form):
|
class I18nForm(forms.Form):
|
||||||
decimal_field = forms.DecimalField()
|
decimal_field = forms.DecimalField(localize=True)
|
||||||
float_field = forms.FloatField()
|
float_field = forms.FloatField(localize=True)
|
||||||
date_field = forms.DateField()
|
date_field = forms.DateField(localize=True)
|
||||||
datetime_field = forms.DateTimeField()
|
datetime_field = forms.DateTimeField(localize=True)
|
||||||
time_field = forms.TimeField()
|
time_field = forms.TimeField(localize=True)
|
||||||
integer_field = forms.IntegerField()
|
integer_field = forms.IntegerField(localize=True)
|
||||||
|
|
||||||
class SelectDateForm(forms.Form):
|
class SelectDateForm(forms.Form):
|
||||||
date_field = forms.DateField(widget=SelectDateWidget)
|
date_field = forms.DateField(widget=SelectDateWidget)
|
||||||
|
|
||||||
class CompanyForm(forms.ModelForm):
|
class CompanyForm(forms.ModelForm):
|
||||||
|
cents_payed = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
|
||||||
|
products_delivered = forms.IntegerField(localize=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Company
|
model = Company
|
||||||
|
|
|
@ -409,7 +409,8 @@ class FormattingTests(TestCase):
|
||||||
self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00')
|
self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00')
|
||||||
self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
|
self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
|
||||||
settings.USE_THOUSAND_SEPARATOR = True
|
settings.USE_THOUSAND_SEPARATOR = True
|
||||||
self.assert_(u'12.000' in form6.as_ul())
|
# Checking for the localized "products_delivered" field
|
||||||
|
self.assert_(u'<input type="text" name="products_delivered" value="12.000" id="id_products_delivered" />' in form6.as_ul())
|
||||||
finally:
|
finally:
|
||||||
deactivate()
|
deactivate()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue