Opened 10 years ago

Closed 6 years ago

Last modified 5 years ago

#3672 closed Uncategorized (fixed)

newforms: DateField doesn't handle date output formats

Reported by: orestis@… Owned by: Adi J. Sieker
Component: Forms Version: master
Severity: Normal Keywords: DateField l10n localization format input output
Cc: scott@…, gary.wilson@…, jesse.lovelace@…, ajs@…, blake@…, andy@…, tao_jonesin@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

As it stands, the when using a newforms.DateField with specified input
formats, it gets parsed alright, but when rendering the form there is
no way to specify the output format, it gets printed as YYYY-MM-DD.

By looking in the source code, I haven't been able to find anything related to this, so I think DateField needs some tweaking.

This not only is a bad localization practice, it makes _using_ the
input formats impossible, since when re-submitting a populated form
without changes, you get validation errors.

Since we can define multiple input formats, but there is only one output format (obviously), I suggest:

a) Defining a new parameter, output_format
b) Make it optional, and set it to the first input format defined in the form field.

Attachments (6)

date-time-formatting-widgets.py (1.1 KB) - added by scott@… 10 years ago.
Widgets that format date or time before rendering
date-time-formatting-widgets.2.py (1.3 KB) - added by scott@… 10 years ago.
Bug fix: If an invalid date or time is entered the widgets don't try to format it
date-time-widgets-tests.diff (4.4 KB) - added by scott@… 9 years ago.
Widgets (slightly remodeled) and tests as a diff
date-time-widgets-tests-2.diff (4.4 KB) - added by Adi J. Sieker 9 years ago.
updated to work with trunk and use translated DATE_FORMAT and TIME_FORMAT as well
date-time-widgets-tests-7601.diff (2.2 KB) - added by Adi J. Sieker 8 years ago.
update the patch again, removed the usage for DATE_FORMAT from the translation.
ticket#3672--patch-test.diff (5.3 KB) - added by Dinoboff 8 years ago.
Patch and test

Download all attachments as: .zip

Change History (29)

comment:1 Changed 10 years ago by Simon G. <dev@…>

Triage Stage: UnreviewedDesign decision needed

comment:2 Changed 10 years ago by scott@…

Cc: scott@… added

I ran in to the same problem today. Seems like maybe this is a job for the widget, rather than the field? My interim solution was to write widgets that derive from TextInput, override render and format the value before it is written out. Code for the widgets is attached.

Usage:

class MyForm(forms.Form):
    date = forms.DateField(widget=DateFormattedTextInput())
    time = forms.TimeField(widget=TimeFormattedTextInput())
    # or pass output format to widget:
    date = forms.DateField(widget=DateFormattedTextInput(format='j M Y'))

Changed 10 years ago by scott@…

Widgets that format date or time before rendering

comment:3 Changed 10 years ago by Ville Säävuori <Ville@…>

I ran into this today.

For me it would be enough to make the field render its content according to input_formats parameter.

But as said, this bug indeed leaves the DateField unusable for now :(

comment:4 Changed 10 years ago by Ville Säävuori <Ville@…>

Whipped up a quick workaround:

First, make timeformat variable

from datetime import date
TIME_FORMAT = '%d.%m.%Y'

then use it in input_formats

date_of_birth = forms.DateField(input_formats=[TIME_FORMAT], label="Date of Birth", required=False, help_text="Format like 17.12.1979")

and when initializing the form, use strftime

date_of_birth = user.get_profile().date_of_birth
form = MyForm(initial={'date_of_birth': date_of_birth.strftime(TIME_FORMAT)})

Not very DRY or pretty, but it seems to work.

comment:5 Changed 10 years ago by Gary Wilson <gary.wilson@…>

Cc: gary.wilson@… added

Changed 10 years ago by scott@…

Bug fix: If an invalid date or time is entered the widgets don't try to format it

comment:6 Changed 10 years ago by anonymous

Cc: jesse.lovelace@… added

comment:7 Changed 9 years ago by James Bennett

See also #3533.

comment:8 Changed 9 years ago by Gary Wilson

Has patch: set
Needs tests: set
Patch needs improvement: set
Triage Stage: Design decision neededAccepted

I'm leaning towards the patch attached to this ticket rather than the one on #3533 since the one here splits the Date and Time widgets and makes use of formats in settings.py.

How about some tests and a patch in diff format.

Changed 9 years ago by scott@…

Widgets (slightly remodeled) and tests as a diff

comment:9 Changed 9 years ago by scott@…

Note that these widgets take a Django style format string like 'N j, Y' versus Python strftime() style like '%b %d, %Y'.

It means you could have a field definition with two different styles of date format strings like:

class MyForm(forms.Form):
    start_date  = forms.DateField(widget=DateTextInput(format='d/m/y'), input_formats=('%d/%m/%y',))

However, I think it makes sense to use Django format strings for output since it is used elsewhere in the UI and is perhaps more powerful. DateField uses strftime() patterns for input, but it is parsing using strptime() so that's the natural format.

comment:10 Changed 9 years ago by David Jones <davesgonebananas@…>

Found this incredibly useful. Have implemented a modified version that uses datetime.strftime and it is working perfectly for me. However, I'm surprised this has been open for 1 year and has not made yet it into trunk.

Changed 9 years ago by Adi J. Sieker

updated to work with trunk and use translated DATE_FORMAT and TIME_FORMAT as well

comment:11 Changed 9 years ago by Adi J. Sieker

Cc: ajs@… added

new patch now works with trunk.

I also changed how the date and time formats are determined.

  1. user supplied
  2. format from translation using ugettext
  3. format from settings.

I also tried to add the new text inputs as default widgets to the DateField and TimeField model fields.
This breaks forms tests and modelforms tests, since the tests supply unicode strings instead of datetime.date or datetime objects to the date and time widgets. The new widgets return None if they are not supplied with a datetime.date or datetime.datetime instances.

Now my question is: Does a widgets have to handle unicode strings (thinking about POST or GET values) or do the widgets always get value from to_python?
Actually thinking about it some more having to handle unicode is probably a must since I can use a Form without a Model.

So I'd leave unicode strings as they are and only format date and datetime instance. Is that OK?

Changed 8 years ago by Adi J. Sieker

update the patch again, removed the usage for DATE_FORMAT from the translation.

comment:12 Changed 8 years ago by Adi J. Sieker

Owner: changed from nobody to Adi J. Sieker

the usage of DATE_FORMAT from the translation or utils.translation.get_date_format doesn't actually make much sense for input control. The german DATE_FORMAT is 12. Apr 2008 which, when displayed in an input control doesn't feel correct.

comment:13 Changed 8 years ago by anonymous

Cc: blake@… added

comment:14 Changed 8 years ago by Dinoboff

Thanks for the patches. I am new to Python and Django can't really understand how all that works.

Here the solution for DateField that I am using; it doesn't rely on settings.DATE_FORMAT but on the field input_formats property:

from django import newforms as forms
from django.newforms.fields import DEFAULT_DATE_INPUT_FORMATS
import datetime

DEFAULT_DATE_OUTPUT_FORMATS = DEFAULT_DATE_INPUT_FORMATS[0]

class FormattedTextInput(forms.widgets.TextInput):
    "Overrides TextInput to render formatted value."
    def render(self, name, value, attrs=None):
        formatted_value = None
        if value:
            formatted_value = self.format_value(value)
        return super(FormattedTextInput, self).render(name, formatted_value, attrs)

class DateFormattedTextInput(FormattedTextInput):
    "Renders formatted date."
    def __init__(self, format=None, attrs=None):
        super(DateFormattedTextInput, self).__init__(attrs)
        self.format = format or DEFAULT_DATE_OUTPUT_FORMATS

    def format_value(self, value):
        if isinstance(value, datetime.date) or isinstance(value, datetime.datetime):
            return value.strftime(self.format)
        else:
            return value

class DateField(forms.DateField):
    widget = DateFormattedTextInput

    def __init__(self, *args, **kwargs):
        super(DateField, self).__init__(*args, **kwargs)
        self.widget.format = self.input_formats[0]

Hope it helps.

Changed 8 years ago by Dinoboff

Patch and test

comment:15 Changed 8 years ago by anonymous

Needs tests: unset
Patch needs improvement: unset

DateTimeField's widget (DateTimeInput) already allows to format date and datetime object.

comment:16 Changed 8 years ago by Thomas Güttler

Cc: hv@… added

comment:17 Changed 8 years ago by marxis.rene@…

milestone: post-1.0

Hello

i think

def format_value(self, value):

if isinstance(value, datetime.date) or isinstance(value, datetime.datetime):

return value.strftime(self.format)

else:

return value

needs to be changed to:

def format_value(self, value):

if isinstance(value, datetime.date) or isinstance(value, datetime.datetime):

try:

return value.strftime(self.format)

except:

return value

else:

return value

Otherwise the value.strftime(self.format) would crash the form (form render returns "") if the field-value does not validate on calling form.is_valid()

If my approach is wrong please let me know. I'm very new to django/python :)

comment:18 Changed 8 years ago by (none)

milestone: post-1.0

Milestone post-1.0 deleted

comment:19 Changed 8 years ago by anonymous

Cc: andy@… added

comment:20 Changed 8 years ago by taojonesin

Cc: tao_jonesin@… added

comment:21 in reply to:  17 Changed 7 years ago by Adam Nelson

Patch needs improvement: set

No response to marxis.rene@googlemail.com yet so marking as patch needs improvement until somebody responds to that issue. Comment 15 marks this as not even relevant anymore - not sure either way.

comment:22 Changed 6 years ago by Ramiro Morales

Resolution: fixed
Status: newclosed

I think these needs were fulfilled with the changes introduced in r11964 (GSoC 2010 project) and further refinements committed later since then.

comment:23 Changed 5 years ago by Thomas Güttler

Cc: hv@… removed
Easy pickings: unset
Severity: Normal
Type: Uncategorized
UI/UX: unset
Note: See TracTickets for help on using tickets.
Back to Top