#21173 closed Bug (fixed)
Django DateTimeInput determines language/locale at startup time but this may change later, resulting in validation errors
Reported by: | Owned by: | Claude Paroz | |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Normal | Keywords: | forms, widgets, locale |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
My application works in two locales, 'nl' and 'en'. In some situations, when editing content, Django formats datetimes in the wrong format which won't validate later.
The problem, I suspect is in the fact that DateTimeInput determines/stores the locale format in its init, which means at startup/import time in most cases. It cannot handle a changing locale later.
This is with Django 1.4.x but the relevant code doesn't appear to be any different on 1.5.x
I've tested/verified the issue in an interactive django shell session:
# In my settings I have LANGUAGE_CODE = 'nl' # but the user can switch to english later. # Forms, fields and widgets are usually initialized at startup/import time # DateTimeField users DateTimeInput which uses the current language to determine the preferred format In [1]: from django.contrib.auth.forms import UserChangeForm In [2]: print UserChangeForm().fields['last_login'].widget.format %d-%m-%Y %H:%M:%S # this is a rather dutch format # imagine the user switches to english In [3]: from django.utils import translation In [4]: translation.activate('en') In [5]: print UserChangeForm().fields['last_login'].widget.format %d-%m-%Y %H:%M:%S # the format remains unchanged, which isn't good but not fatal. Let's format a string using this In [6]: from datetime import datetime In [7]: now = datetime.now() In [8]: print UserChangeForm().fields['last_login'].widget._format_value(now) 26-09-2013 15:33:13 # now feed this string back to the field, as if the form was filled in and then submitted without change In [11]: print UserChangeForm().fields['last_login'].to_python("26-09-2013 15:33:13") --------------------------------------------------------------------------- ValidationError Traceback (most recent call last) /home/ivo/.buildout/eggs/Django-1.4.5-py2.7.egg/django/core/management/commands/shell.pyc in <module>() ----> 1 print UserChangeForm().fields['last_login'].to_python("26-09-2013 15:33:13") /home/ivo/.buildout/eggs/Django-1.4.5-py2.7.egg/django/forms/fields.pyc in to_python(self, value) 435 return None 436 value = '%s %s' % tuple(value) --> 437 result = super(DateTimeField, self).to_python(value) 438 return from_current_timezone(result) 439 /home/ivo/.buildout/eggs/Django-1.4.5-py2.7.egg/django/forms/fields.pyc in to_python(self, value) 354 except ValueError: 355 continue --> 356 raise ValidationError(self.error_messages['invalid']) 357 358 def strptime(self, value, format): ValidationError: [u'Enter a valid date/time.'] # oops!
Change History (9)
comment:1 by , 11 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 11 years ago
comment:3 by , 11 years ago
Form initialization kicks in at startup / import time, LocaleMiddleWare doesn't happen until the first request.
LocaleMiddleware may activate a different language than the widget was initialized with.
comment:4 by , 11 years ago
I think the basic issue is that widget.is_localized
is False by default, and contrib.auth forms doesn't set it. In your own forms, you can probably activate is_localized
and the self.format
variable set in the __init__
method will not be used.
Personally, I'd vote for setting is_localized
to the settings.USE_L10N
value by default. But this might be backwards incompatible.
A more contained fix would be to let self.format
to None when it is not specified in the widget constructor, and then getting the format only if and when it is needed in _format_value
.
comment:5 by , 11 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Version: | 1.4 → master |
comment:6 by , 11 years ago
Has patch: | set |
---|
Pull request: https://github.com/django/django/pull/1720
Isn't less code better :-)
comment:7 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
comment:8 by , 10 years ago
Any chance this makes it into 1.6? It's a pretty serious issue where the user accessing the page with a different language preference breaks date(time) fields in all forms.
comment:9 by , 10 years ago
I noticed that now date and time widgets ignore is_localized and always localize. I like this, but I haven't seen it discussed, so I wondered whether this was an oversight. Previous behaviour was to use the first format for the LANGUAGE_CODE in settings.py as a default format that'll change only when overridden manually or when is_localized is True.
I think it makes sense this way around. If you need a certain format instead of a localized one, it should be controlled by passing format to the widget, not by settings.LANGUAGE_CODE.
AFAIK determining locale at the form initialization phase shouldn't cause any issues because
LocaleMiddleware
already activated the current language.How are you activating user specific language in your application?