Ticket #13621: ticket13621.diff

File ticket13621.diff, 12.1 KB (added by zerok, 5 years ago)
  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index 1f8ff6d..9c5379a 100644
    a b from django import forms, template 
    22from django.forms.formsets import all_valid
    33from django.forms.models import modelform_factory, modelformset_factory, inlineformset_factory
    44from django.forms.models import BaseInlineFormSet
     5from django.conf import settings
    56from django.contrib.contenttypes.models import ContentType
    67from django.contrib.admin import widgets
    78from django.contrib.admin import helpers
    class BaseModelAdmin(object): 
    116117        for klass in db_field.__class__.mro():
    117118            if klass in self.formfield_overrides:
    118119                kwargs = dict(self.formfield_overrides[klass], **kwargs)
     120                if settings.USE_L10N and 'localize' not in kwargs:
     121                    kwargs['localize']=True
    119122                return db_field.formfield(**kwargs)
    120123
    121124        # For any other type of field, just call its formfield() method.
     125        if settings.USE_L10N and 'localize' not in kwargs:
     126            kwargs['localize'] = True
    122127        return db_field.formfield(**kwargs)
    123128
    124129    def formfield_for_choice_field(self, db_field, request=None, **kwargs):
  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 0bae4ba..0026f59 100644
    a b class Field(object): 
    107107        self.localize = localize
    108108        if self.localize:
    109109            widget.is_localized = True
     110        if hasattr(self, 'input_formats'):
     111            widget.input_formats = self.input_formats
    110112
    111113        # Hook into self.widget_attrs() for any Field-specific HTML attributes.
    112114        extra_attrs = self.widget_attrs(widget)
    class DateField(Field): 
    323325    }
    324326
    325327    def __init__(self, input_formats=None, *args, **kwargs):
    326         super(DateField, self).__init__(*args, **kwargs)
    327328        self.input_formats = input_formats
     329        super(DateField, self).__init__(*args, **kwargs)
    328330
    329331    def to_python(self, value):
    330332        """
    class TimeField(Field): 
    351353    }
    352354
    353355    def __init__(self, input_formats=None, *args, **kwargs):
    354         super(TimeField, self).__init__(*args, **kwargs)
    355356        self.input_formats = input_formats
     357        super(TimeField, self).__init__(*args, **kwargs)
    356358
    357359    def to_python(self, value):
    358360        """
    class DateTimeField(Field): 
    377379    }
    378380
    379381    def __init__(self, input_formats=None, *args, **kwargs):
    380         super(DateTimeField, self).__init__(*args, **kwargs)
    381382        self.input_formats = input_formats
     383        super(DateTimeField, self).__init__(*args, **kwargs)
    382384
    383385    def to_python(self, value):
    384386        """
  • django/forms/widgets.py

    diff --git a/django/forms/widgets.py b/django/forms/widgets.py
    index e3799c6..f9ed445 100644
    a b class Widget(object): 
    134134    is_hidden = False          # Determines whether this corresponds to an <input type="hidden">.
    135135    needs_multipart_form = False # Determines does this widget need multipart-encrypted form
    136136    is_localized = False
     137    input_formats = None # Input formats explicitly specified for the form field
    137138
    138139    def __init__(self, attrs=None):
    139140        if attrs is not None:
    class Textarea(Widget): 
    302303
    303304class DateInput(Input):
    304305    input_type = 'text'
    305     format = '%Y-%m-%d'     # '2006-10-25'
     306    fallback_format = '%Y-%m-%d'     # '2006-10-25'
     307    format = None
    306308
    307309    def __init__(self, attrs=None, format=None):
    308310        super(DateInput, self).__init__(attrs)
    class DateInput(Input): 
    310312            self.format = format
    311313
    312314    def _format_value(self, value):
     315        base_format = self.format
     316        if self.format is None and self.input_formats:
     317            base_format = self.input_formats[0]
     318
    313319        if self.is_localized:
    314             return formats.localize_input(value)
     320            return formats.localize_input(value, default=base_format)
    315321        elif hasattr(value, 'strftime'):
    316322            value = datetime_safe.new_date(value)
    317             return value.strftime(self.format)
     323            return value.strftime(base_format is not None\
     324                    and base_format or self.fallback_format)
    318325        return value
    319326
    320327    def _has_changed(self, initial, data):
    class DateInput(Input): 
    330337
    331338class DateTimeInput(Input):
    332339    input_type = 'text'
    333     format = '%Y-%m-%d %H:%M:%S'     # '2006-10-25 14:30:59'
     340    fallback_format = '%Y-%m-%d %H:%M:%S'     # '2006-10-25 14:30:59'
     341    format = None
    334342
    335343    def __init__(self, attrs=None, format=None):
    336344        super(DateTimeInput, self).__init__(attrs)
    class DateTimeInput(Input): 
    338346            self.format = format
    339347
    340348    def _format_value(self, value):
     349        base_format = self.format
     350        if self.format is None and self.input_formats:
     351            base_format = self.input_formats[0]
     352
    341353        if self.is_localized:
    342             return formats.localize_input(value)
     354            return formats.localize_input(value, default=base_format)
    343355        elif hasattr(value, 'strftime'):
    344356            value = datetime_safe.new_datetime(value)
    345             return value.strftime(self.format)
     357            return value.strftime(base_format is not None\
     358                    and base_format or self.fallback_format)
    346359        return value
    347360
    348361    def _has_changed(self, initial, data):
    class DateTimeInput(Input): 
    358371
    359372class TimeInput(Input):
    360373    input_type = 'text'
    361     format = '%H:%M:%S'     # '14:30:59'
     374    fallback_format = '%H:%M:%S'     # '14:30:59'
     375    format = None
    362376
    363377    def __init__(self, attrs=None, format=None):
    364378        super(TimeInput, self).__init__(attrs)
    class TimeInput(Input): 
    366380            self.format = format
    367381
    368382    def _format_value(self, value):
     383        base_format = self.format
     384        if self.format is None and self.input_formats:
     385            base_format = self.input_formats[0]
     386
    369387        if self.is_localized:
    370             return formats.localize_input(value)
     388            return formats.localize_input(value, default=base_format)
    371389        elif hasattr(value, 'strftime'):
    372             return value.strftime(self.format)
     390            return value.strftime(base_format is not None\
     391                    and base_format or self.fallback_format)
    373392        return value
    374393
    375394    def _has_changed(self, initial, data):
    class SplitDateTimeWidget(MultiWidget): 
    764783            return [value.date(), value.time().replace(microsecond=0)]
    765784        return [None, None]
    766785
     786    def set_date_format(self, fmt):
     787        self.widgets[0].format = fmt
     788
     789    def set_time_format(self, fmt):
     790        self.widgets[1].format = fmt
     791
    767792class SplitHiddenDateTimeWidget(SplitDateTimeWidget):
    768793    """
    769794    A Widget that splits datetime input into two <input type="hidden"> inputs.
  • tests/regressiontests/forms/fields.py

    diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
    index 990a9f7..bbd251a 100644
    a b class FieldsTests(TestCase): 
    350350        self.assertEqual(None, f.clean(''))
    351351        self.assertEqual('None', repr(f.clean('')))
    352352
     353    def test_ticket13621_localized_inputformats(self):
     354        # Explicit input formats should have precedence over any
     355        # other format specification.
     356
     357        f = TimeField(input_formats=["%I:%M %p"], widget=TimeInput,
     358                localize=True)
     359        result = f.clean('1:30 PM')
     360        self.assertNotEqual(None, result)
     361        text = f.widget._format_value(result)
     362        self.assertNotEqual(None, f.clean(text))
     363
     364        f = DateTimeField(input_formats=["%I:%M %p"], localize=True)
     365        result = f.clean('1:30 PM')
     366        text = f.widget._format_value(result)
     367        f.clean(text)
     368        self.assertNotEqual(None, f.clean(text))
     369
     370        f = DateField(input_formats=["%I:%M %p"], localize=True)
     371        result = f.clean('1:30 PM')
     372        text = f.widget._format_value(result)
     373        f.clean(text)
     374        self.assertNotEqual(None, f.clean(text))
     375
     376        # If no localization should be used and input_formats are
     377        # provided, use them (or actually the first in the list).
     378
     379
     380        f = DateTimeField(input_formats=["%I:%M %p"], localize=False)
     381        result = f.clean('1:30 PM')
     382        text = f.widget._format_value(result)
     383        f.clean(text)
     384        self.assertNotEqual(None, f.clean(text))
     385
     386        f = DateField(input_formats=["%I:%M %p"], localize=False)
     387        result = f.clean('1:30 PM')
     388        text = f.widget._format_value(result)
     389        f.clean(text)
     390        self.assertNotEqual(None, f.clean(text))
     391
     392        f = TimeField(widget=TimeInput)
     393        result = f.clean('12:30:00')
     394        self.assertNotEqual(None, result)
     395        text = f.widget._format_value(result)
     396        self.assertNotEqual(None, f.clean(text))
     397
     398        f = DateTimeField()
     399        result = f.clean('2006-10-25 12:30:00')
     400        self.assertNotEqual(None, result)
     401        text = f.widget._format_value(result)
     402        self.assertNotEqual(None, f.clean(text))
     403
     404    def test_ticket13621_timefield_notlocalized(self):
     405        f = TimeField(input_formats=["%I:%M %p"], widget=TimeInput,
     406                localize=False)
     407        result = f.clean('1:30 PM')
     408        self.assertNotEqual(None, result)
     409        text = f.widget._format_value(result)
     410        self.assertNotEqual(None, f.clean(text))
     411
     412    def test_ticket13621_datefield_fallback(self):
     413        f = DateField(widget=DateInput)
     414        result = f.clean('2006-10-25')
     415        self.assertNotEqual(None, result)
     416        text = f.widget._format_value(result)
     417        self.assertNotEqual(None, f.clean(text))
     418
     419    def test_ticket13621_timefield_globally_localized(self):
     420        """
     421        Test if the timeinput widgets produces the same output format that it
     422        accepts as input when set using a format module.
     423        """
     424        from django.utils import formats
     425        from django.conf import settings
     426        old_setting = settings.USE_L10N
     427        settings.USE_L10N = True
     428        _get_format_modules = formats.get_format_modules
     429        try:
     430            # We have to do a bit of mocking here to get into the L10N system
     431            # properly.
     432            class _GetFormatModules(object):
     433                mock_format_modules = None
     434
     435                def __call__(self, reverse=False):
     436                    if self.mock_format_modules is None:
     437                        return _get_format_modules(reverse)
     438                    return reverse and reversed(self.mock_format_modules)\
     439                            or self.mock_format_modules
     440
     441            class MockFormatModule(object):
     442                TIME_INPUT_FORMATS = ["%I:%M %p"]
     443                DATE_INPUT_FORMATS = ["%I:%M %p"]
     444                DATETIME_INPUT_FORMATS = ["%I:%M %p"]
     445
     446            formats.get_format_modules = _GetFormatModules()
     447            formats.get_format_modules.mock_format_modules = [
     448                    MockFormatModule()]
     449
     450            f = TimeField(localize=True)
     451            result = f.clean('1:30 PM')
     452            f.clean(f.widget._format_value(result))
     453
     454            f = DateField(localize=True)
     455            result = f.clean('1:30 PM')
     456            f.clean(f.widget._format_value(result))
     457
     458            f = DateTimeField(localize=True)
     459            result = f.clean('1:30 PM')
     460            f.clean(f.widget._format_value(result))
     461
     462            # If an explicit input format is provided, use that
     463
     464            f = TimeField(input_formats=["%I"], localize=True)
     465            result = f.clean('1')
     466            f.clean(f.widget._format_value(result))
     467
     468            f = DateField(input_formats=["%I"], localize=True)
     469            result = f.clean('1')
     470            f.clean(f.widget._format_value(result))
     471
     472            f = DateTimeField(input_formats=["%I"], localize=True)
     473            result = f.clean('1')
     474            f.clean(f.widget._format_value(result))
     475        finally:
     476            formats.get_format_modules = _get_format_modules
     477            settings.USE_L10N = old_setting
     478
     479
    353480    # RegexField ##################################################################
    354481
    355482    def test_regexfield_27(self):
Back to Top