mirror of
https://github.com/django/django.git
synced 2025-10-25 06:36:07 +00:00
Fixed #7980 - Improved i18n framework to support locale aware formatting (dates and numbers) and form processing.
Thanks to Marc Garcia for working on this during his Google Summer of Code 2009! Additionally fixes #1061, #2203, #3940, #5526, #6449, #6231, #6693, #6783, #9366 and #10891. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11964 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -8,6 +8,8 @@ import re
|
||||
from django.forms.widgets import Widget, Select
|
||||
from django.utils.dates import MONTHS
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.formats import get_format
|
||||
from django.conf import settings
|
||||
|
||||
__all__ = ('SelectDateWidget',)
|
||||
|
||||
@@ -45,38 +47,27 @@ class SelectDateWidget(Widget):
|
||||
if match:
|
||||
year_val, month_val, day_val = [int(v) for v in match.groups()]
|
||||
|
||||
choices = [(i, i) for i in self.years]
|
||||
year_html = self.create_select(name, self.year_field, value, year_val, choices)
|
||||
choices = MONTHS.items()
|
||||
month_html = self.create_select(name, self.month_field, value, month_val, choices)
|
||||
choices = [(i, i) for i in range(1, 32)]
|
||||
day_html = self.create_select(name, self.day_field, value, day_val, choices)
|
||||
|
||||
format = get_format('DATE_FORMAT')
|
||||
escaped = False
|
||||
output = []
|
||||
|
||||
if 'id' in self.attrs:
|
||||
id_ = self.attrs['id']
|
||||
else:
|
||||
id_ = 'id_%s' % name
|
||||
|
||||
month_choices = MONTHS.items()
|
||||
if not (self.required and value):
|
||||
month_choices.append(self.none_value)
|
||||
month_choices.sort()
|
||||
local_attrs = self.build_attrs(id=self.month_field % id_)
|
||||
s = Select(choices=month_choices)
|
||||
select_html = s.render(self.month_field % name, month_val, local_attrs)
|
||||
output.append(select_html)
|
||||
|
||||
day_choices = [(i, i) for i in range(1, 32)]
|
||||
if not (self.required and value):
|
||||
day_choices.insert(0, self.none_value)
|
||||
local_attrs['id'] = self.day_field % id_
|
||||
s = Select(choices=day_choices)
|
||||
select_html = s.render(self.day_field % name, day_val, local_attrs)
|
||||
output.append(select_html)
|
||||
|
||||
year_choices = [(i, i) for i in self.years]
|
||||
if not (self.required and value):
|
||||
year_choices.insert(0, self.none_value)
|
||||
local_attrs['id'] = self.year_field % id_
|
||||
s = Select(choices=year_choices)
|
||||
select_html = s.render(self.year_field % name, year_val, local_attrs)
|
||||
output.append(select_html)
|
||||
|
||||
for char in format:
|
||||
if escaped:
|
||||
escaped = False
|
||||
elif char == '\\':
|
||||
escaped = True
|
||||
elif char in 'Yy':
|
||||
output.append(year_html)
|
||||
elif char in 'bFMmNn':
|
||||
output.append(month_html)
|
||||
elif char in 'dj':
|
||||
output.append(day_html)
|
||||
return mark_safe(u'\n'.join(output))
|
||||
|
||||
def id_for_label(self, id_):
|
||||
@@ -90,5 +81,27 @@ class SelectDateWidget(Widget):
|
||||
if y == m == d == "0":
|
||||
return None
|
||||
if y and m and d:
|
||||
return '%s-%s-%s' % (y, m, d)
|
||||
if settings.USE_L10N:
|
||||
input_format = get_format('DATE_INPUT_FORMATS')[0]
|
||||
try:
|
||||
date_value = datetime.date(int(y), int(m), int(d))
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
return date_value.strftime(input_format)
|
||||
else:
|
||||
return '%s-%s-%s' % (y, m, d)
|
||||
return data.get(name, None)
|
||||
|
||||
def create_select(self, name, field, value, val, choices):
|
||||
if 'id' in self.attrs:
|
||||
id_ = self.attrs['id']
|
||||
else:
|
||||
id_ = 'id_%s' % name
|
||||
if not (self.required and value):
|
||||
choices.insert(0, self.none_value)
|
||||
local_attrs = self.build_attrs(id=field % id_)
|
||||
s = Select(choices=choices)
|
||||
select_html = s.render(field % name, val, local_attrs)
|
||||
return select_html
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import os
|
||||
import re
|
||||
import time
|
||||
import urlparse
|
||||
import warnings
|
||||
from decimal import Decimal, DecimalException
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
@@ -17,6 +18,7 @@ import django.core.exceptions
|
||||
import django.utils.copycompat as copy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_unicode, smart_str
|
||||
from django.utils.formats import get_format
|
||||
|
||||
from util import ErrorList, ValidationError
|
||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
|
||||
@@ -36,6 +38,20 @@ __all__ = (
|
||||
# These values, if given to to_python(), will trigger the self.required check.
|
||||
EMPTY_VALUES = (None, '')
|
||||
|
||||
def en_format(name):
|
||||
"""
|
||||
Helper function to stay backward compatible.
|
||||
"""
|
||||
from django.conf.locale.en import formats
|
||||
warnings.warn(
|
||||
"`django.forms.fields.DEFAULT_%s` is deprecated; use `django.utils.formats.get_format('%s')` instead." % (name, name),
|
||||
PendingDeprecationWarning
|
||||
)
|
||||
return getattr(formats, name)
|
||||
|
||||
DEFAULT_DATE_INPUT_FORMATS = en_format('DATE_INPUT_FORMATS')
|
||||
DEFAULT_TIME_INPUT_FORMATS = en_format('TIME_INPUT_FORMATS')
|
||||
DEFAULT_DATETIME_INPUT_FORMATS = en_format('DATETIME_INPUT_FORMATS')
|
||||
|
||||
class Field(object):
|
||||
widget = TextInput # Default widget to use when rendering this type of Field.
|
||||
@@ -200,7 +216,9 @@ class FloatField(Field):
|
||||
if not self.required and value in EMPTY_VALUES:
|
||||
return None
|
||||
try:
|
||||
value = float(value)
|
||||
# We always accept dot as decimal separator
|
||||
if isinstance(value, str) or isinstance(value, unicode):
|
||||
value = float(value.replace(get_format('DECIMAL_SEPARATOR'), '.'))
|
||||
except (ValueError, TypeError):
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
if self.max_value is not None and value > self.max_value:
|
||||
@@ -236,7 +254,9 @@ class DecimalField(Field):
|
||||
return None
|
||||
value = smart_str(value).strip()
|
||||
try:
|
||||
value = Decimal(value)
|
||||
# We always accept dot as decimal separator
|
||||
if isinstance(value, str) or isinstance(value, unicode):
|
||||
value = Decimal(value.replace(get_format('DECIMAL_SEPARATOR'), '.'))
|
||||
except DecimalException:
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
|
||||
@@ -264,14 +284,6 @@ class DecimalField(Field):
|
||||
raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
|
||||
return value
|
||||
|
||||
DEFAULT_DATE_INPUT_FORMATS = (
|
||||
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
|
||||
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
|
||||
'%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
|
||||
'%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
|
||||
'%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
|
||||
)
|
||||
|
||||
class DateField(Field):
|
||||
widget = DateInput
|
||||
default_error_messages = {
|
||||
@@ -280,7 +292,7 @@ class DateField(Field):
|
||||
|
||||
def __init__(self, input_formats=None, *args, **kwargs):
|
||||
super(DateField, self).__init__(*args, **kwargs)
|
||||
self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
|
||||
self.input_formats = input_formats
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
@@ -294,18 +306,13 @@ class DateField(Field):
|
||||
return value.date()
|
||||
if isinstance(value, datetime.date):
|
||||
return value
|
||||
for format in self.input_formats:
|
||||
for format in self.input_formats or get_format('DATE_INPUT_FORMATS'):
|
||||
try:
|
||||
return datetime.date(*time.strptime(value, format)[:3])
|
||||
except ValueError:
|
||||
continue
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
|
||||
DEFAULT_TIME_INPUT_FORMATS = (
|
||||
'%H:%M:%S', # '14:30:59'
|
||||
'%H:%M', # '14:30'
|
||||
)
|
||||
|
||||
class TimeField(Field):
|
||||
widget = TimeInput
|
||||
default_error_messages = {
|
||||
@@ -314,7 +321,7 @@ class TimeField(Field):
|
||||
|
||||
def __init__(self, input_formats=None, *args, **kwargs):
|
||||
super(TimeField, self).__init__(*args, **kwargs)
|
||||
self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
|
||||
self.input_formats = input_formats
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
@@ -326,25 +333,13 @@ class TimeField(Field):
|
||||
return None
|
||||
if isinstance(value, datetime.time):
|
||||
return value
|
||||
for format in self.input_formats:
|
||||
for format in self.input_formats or get_format('TIME_INPUT_FORMATS'):
|
||||
try:
|
||||
return datetime.time(*time.strptime(value, format)[3:6])
|
||||
except ValueError:
|
||||
continue
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
|
||||
DEFAULT_DATETIME_INPUT_FORMATS = (
|
||||
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
|
||||
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
|
||||
'%Y-%m-%d', # '2006-10-25'
|
||||
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
|
||||
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
|
||||
'%m/%d/%Y', # '10/25/2006'
|
||||
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
|
||||
'%m/%d/%y %H:%M', # '10/25/06 14:30'
|
||||
'%m/%d/%y', # '10/25/06'
|
||||
)
|
||||
|
||||
class DateTimeField(Field):
|
||||
widget = DateTimeInput
|
||||
default_error_messages = {
|
||||
@@ -353,7 +348,7 @@ class DateTimeField(Field):
|
||||
|
||||
def __init__(self, input_formats=None, *args, **kwargs):
|
||||
super(DateTimeField, self).__init__(*args, **kwargs)
|
||||
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
|
||||
self.input_formats = input_formats
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
@@ -373,7 +368,7 @@ class DateTimeField(Field):
|
||||
if len(value) != 2:
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
value = '%s %s' % tuple(value)
|
||||
for format in self.input_formats:
|
||||
for format in self.input_formats or get_format('DATETIME_INPUT_FORMATS'):
|
||||
try:
|
||||
return datetime.datetime(*time.strptime(value, format)[:6])
|
||||
except ValueError:
|
||||
|
||||
@@ -10,6 +10,7 @@ from django.utils.html import escape, conditional_escape
|
||||
from django.utils.translation import ugettext
|
||||
from django.utils.encoding import StrAndUnicode, force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.formats import localize
|
||||
from django.utils import datetime_safe
|
||||
from datetime import time
|
||||
from util import flatatt
|
||||
@@ -208,7 +209,7 @@ class Input(Widget):
|
||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||
if value != '':
|
||||
# Only add the 'value' attribute if a value is non-empty.
|
||||
final_attrs['value'] = force_unicode(value)
|
||||
final_attrs['value'] = force_unicode(localize(value, is_input=True))
|
||||
return mark_safe(u'<input%s />' % flatatt(final_attrs))
|
||||
|
||||
class TextInput(Input):
|
||||
|
||||
Reference in New Issue
Block a user