mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	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:
		| @@ -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,6 +222,7 @@ 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 | ||||||
|  |         if self.localize: | ||||||
|             value = formats.sanitize_separators(value) |             value = formats.sanitize_separators(value) | ||||||
|         try: |         try: | ||||||
|             value = int(str(value)) |             value = int(str(value)) | ||||||
| @@ -233,6 +243,7 @@ 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 | ||||||
|  |         if self.localize: | ||||||
|             value = formats.sanitize_separators(value) |             value = formats.sanitize_separators(value) | ||||||
|         try: |         try: | ||||||
|             value = float(value) |             value = float(value) | ||||||
| @@ -268,6 +279,7 @@ class DecimalField(Field): | |||||||
|         """ |         """ | ||||||
|         if value in validators.EMPTY_VALUES: |         if value in validators.EMPTY_VALUES: | ||||||
|             return None |             return None | ||||||
|  |         if self.localize: | ||||||
|             value = formats.sanitize_separators(value) |             value = formats.sanitize_separators(value) | ||||||
|         value = smart_str(value).strip() |         value = smart_str(value).strip() | ||||||
|         try: |         try: | ||||||
|   | |||||||
| @@ -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() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user