Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enter a valid date/time. #77

Open
glennpierce opened this issue Jul 30, 2015 · 8 comments
Open

Enter a valid date/time. #77

glennpierce opened this issue Jul 30, 2015 · 8 comments

Comments

@glennpierce
Copy link

Hi I have setup a form widget like

dt = forms.DateTimeField("Export start time",
widget=DateTimeWidget(usel10n=True, bootstrap_version=3))

The format I chose in formats.py is chosen correctly. I can change the format and the widget changes
when choosing a date. On submit though I always get "Enter a valid date/time."

Any suggestions ?

Thanks

@johanneshk
Copy link

Same here, maybe this is an issue with different localizations / conversion between localizations?!

EDIT: Solution (?): Specify input format for the DateField:

deadline = forms.DateField(input_formats = ["%d.%m.%Y"], required = True, widget=DateWidget(usel10n=True, bootstrap_version=3,))

Now I specify the localized date format and it works for me. Is it possible to specify this automatically!?

@tylerecouture
Copy link

I'm also having this problem. If I leave the widget format as the default, the day and month are swapped when saved, if I try to specify any sort of format in the widget, I get the error "Enter a valid date/time."

@johanneshk
Copy link

The datewidget simply passes a string (as given on the UI) to the DateField. The DateField first checks if it got a datetime.date(time), which is not the case. Then it tries to parse the string by testing different format specifiers. In my case the format specifier used by the datewidget was not defined in the DateField, so I defined this by hand (see above). What's not so nice is that you would need to specify a format for the DateField for each possible localization, this should somehow work automatically, e.g. if the datewidget did not pass a string but already a datetime.date object.

I assume that the swapping of day and month is because e.g. datewidget use "%d/%m/%Y" and DateField assumes "%m/%d/%Y".

In my case I only have one localization so it's ok for now.

@netinsideout
Copy link

The problem in init method of PickerWidgetMixin when language string converted to js objects. Init in django enviroment with following code

date_start = forms.DateTimeField(label=_("Date Start"), widget=DateTimeWidget(usel10n=True, bootstrap_version=3), required=False)

called only once, when application loading, and not per request. Actually now, with example from documentation django-datetime-widget does not support locale changes per requests, you need to manually call widget initialization per request to change locale of widget and have true support of l18n. I think this is main problem of ValidationErrors on l18n-enabled sites.

@michaeljones
Copy link
Contributor

Great catch, I suspect this is my fault from my opinionated refactor a while back. I moved some of the code into the __init__ as I clearly failed to realise some of the details might change from request to request. We should change that back.

@netinsideout
Copy link

This class works fine for me on l18n-enabled site.

class PickerWidgetMixin(object):

    format_name = None
    glyphicon = None

    def __init__(self, attrs=None, options=None, usel10n=None, bootstrap_version=None):
        if bootstrap_version in [2,3]:
            self.bootstrap_version = bootstrap_version
        else:
            # default 2 to mantain support to old implemetation of django-datetime-widget
            self.bootstrap_version = 2

        if attrs is None:
            attrs = {'readonly': ''}

        self.options = options

        self.format = None
        self.usel10n = usel10n

        if not usel10n and 'format' in self.options:
            # We want to have a Javascript style date format specifier in the options dictionary and we
            # want a Python style date format specifier as a member variable for parsing the date string
            # from the form data
            self.format = toPython_re.sub(
                lambda x: dateConversiontoPython[x.group()],
                self.options['format']
                )
        else:
            self.format = None

        super(PickerWidgetMixin, self).__init__(attrs, format=self.format)

    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs)
        rendered_widget = super(PickerWidgetMixin, self).render(name, value, final_attrs)

        language = get_supported_language(get_language())
        self.options['language'] = language

        if self.usel10n or not self.format:
            self.format = get_format(self.format_name)[0]
            self.options['format'] = toJavascript_re.sub(
                lambda x: dateConversiontoJavascript[x.group()],
                self.format
                )

        #if not set, autoclose have to be true.
        self.options.setdefault('autoclose', True)

        # Build javascript options out of python dictionary
        options_list = []
        for key, value in iter(self.options.items()):
            options_list.append("%s: %s" % (key, quote(key, value)))

        js_options = ",\n".join(options_list)

        # Use provided id or generate hex to avoid collisions in document
        id = final_attrs.get('id', uuid.uuid4().hex)

        clearBtn = quote('clearBtn', self.options.get('clearBtn', 'true')) == 'true'

        return mark_safe(
            BOOTSTRAP_INPUT_TEMPLATE[self.bootstrap_version]
                % dict(
                    id=id,
                    rendered_widget=rendered_widget,
                    clear_button=CLEAR_BTN_TEMPLATE[self.bootstrap_version] if clearBtn else "",
                    glyphicon=self.glyphicon,
                    options=js_options
                    )
        )

    def _media(self):

        js = ["js/bootstrap-datetimepicker.js"]

        language = get_supported_language(get_language())
        if language != 'en':
            js.append("js/locales/bootstrap-datetimepicker.%s.js" % language)

        return widgets.Media(
            css={
                'all': ('css/datetimepicker.css',)
                },
            js=js
            )

    media = property(_media)

@javaghost
Copy link

While using DateTimeInput (default for admin) it actually splits the date and time fields as id_fieldName_0 as date field and id_fieldName_1 as time field. When this DateTimeWidget is used, the post data contains only fieldName as single value, when django expects list of values. Hence in django admin, DateTimeWidget will always throw ValidationError to send values as list. (Tested in Django 1.8 with l10n false in settings)

@silentjay
Copy link

silentjay commented Jun 5, 2017

Is there a fix for this? I'm getting this error with a DateTimeField and looking at this comment thread I'm no closer to finding a fix.

Update: Seems the widget is adding apostrophes around the value e.g. "'2016-03-21 11:00:00'" which is causing the validation failure. Is there anyway to disable this?

altimore pushed a commit to altimore/django-datetime-widget that referenced this issue Mar 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants