使 Django forms.DateField 显示使用本地日期格式

Posted

技术标签:

【中文标题】使 Django forms.DateField 显示使用本地日期格式【英文标题】:Making Django forms.DateField show use local date format 【发布时间】:2010-11-30 00:26:54 【问题描述】:

我正在尝试找到一种简单的方法来构建以澳大利亚格式 (dd/mm/yyyy) 显示日期的表单。这是我能找到的唯一方法。似乎应该有更好的解决方案。

注意事项:

创建了一个以 dd/mm/yyyy 格式呈现日期值的新小部件 创建了新的日期字段以将定位日期格式字符串添加到它尝试使用的值列表中

我认为理想的解决方案是自动本地化的日期字段,但这对我不起作用(strftime 似乎对 unicode 不友好,但我没有很努力)

我错过了什么吗?有没有更优雅的解决方案?这是一种稳健的方法吗?

from models import *
from django import forms
import datetime

class MyDateWidget(forms.TextInput):

    def render(self, name, value, attrs=None):

            if isinstance(value, datetime.date):
                    value=value.strftime("%d/%m/%Y")

            return super(MyDateWidget, self).render(name, value, attrs)


class MyDateField(forms.DateField):

    widget = MyDateWidget

    def __init__(self, *args, **kwargs):
            super(MyDateField, self).__init__(*args, **kwargs)
            self.input_formats = ("%d/%m/%Y",)+(self.input_formats)


class ExampleForm(ModelForm):
    class Meta: 
            model=MyModel
            fields=('name', 'date_of_birth')

    date_of_birth = MyDateField()

【问题讨论】:

一个简单的替代方法是依靠 javascript 日历小部件来进行本地化。我们使用的一个只是隐藏我的日期字段并使用指定的本地格式创建另一个。 关于特定小部件和连接小部件的任何信息? 我想我应该参考***问题:***.com/questions/114068/…。 我在下面的回答提供了一种比覆盖小部件格式更通用的方法。 【参考方案1】:

当然,我不是 django/python 绝地,但是...

我认为您的方法没有任何问题。这是一个干净的阅读。

您可能不需要创建自己的小部件来在第一个表单显示上以正确的格式呈现日期。只需将format 参数用于DateInput 小部件,就可以了。因此,在您的 MyDateField 课程中,我会这样做:

class MyDateField(forms.DateField):

    widget = forms.DateInput(format="%d/%m/%Y")

    def __init__(self, *args, **kwargs):
        super(MyDateField, self).__init__(*args, **kwargs)
        self.input_formats = ("%d/%m/%Y",)+(self.input_formats)

您可以使用formfield_callback(请参阅accepted answer 了解这个遥远相关的问题),意思是:

def customize_fields(f):
    if isinstance(f, DateTimeField):
        datetime_field=forms.DateTimeField(widget=
            forms.DateInput(format='%d/%m/%Y %h:%i'))
        date_field.input_formats = ("%d/%m/%Y %h:%i",)+
            (date_field.input_formats)
        return datetime_field
    elif isinstance(f, DateField):
        date_field=forms.DateField(widget=
            forms.DateInput(format='%d/%m/%Y'))
        date_field.input_formats = ("%d/%m/%Y",)+
            (date_field.input_formats)
        return date_field
    else:
        return f.formfield()

class MyModelForm(forms.ModelForm):
    formfield_callback = customize_fields

    class Meta:
        model = ...

这样做完全消除了对 MyDateField 类的需求,但可能会引入 - 如果您希望每个表单类都调用 customize_fields - 需要 ModelForm 后代,将 formfield_callback=customize_fields 实现为所有的新基础你的表单类。

我使用formfield_callback 机制的问题有两个方面:

    它的可读性较差,并且依赖于对 ModelForms 内部工作原理的了解。我在任何地方都找不到关于 formfield_callback 的实际文档...

    如果您需要在 ModelForm 中重新定义模型字段,可以说使该特定表单实例不需要该字段,如下所示:

       class MyModelForm(forms.ModelForm):
           formfield_callback = customize_fields
           foo = forms.DateField(required=false)
    
           class Meta:
               model = Bar
    

    您正在覆盖customize_fields 返回的表单字段,因此完全失去了自定义。

我认为您的方法更具可读性。

【讨论】:

【参考方案2】:

我以前用过这种简单的方法:只需在 Form 的 init 中设置 DateField.widget 的 'format' 属性:

    class ExampleForm(ModelForm):

        class Meta:
            model = MyModel

        def __init__(self, *args, **kwargs):
            super(ModelForm, self).__init__(*args, **kwargs)
            self.fields['date_of_birth'].widget.format = '%d/%m/%Y'

            # at the same time, set the input format on the date field like you want it:
            self.fields['date_of_birth'].input_formats = ['%d/%m/%Y']

【讨论】:

【参考方案3】:

所有自定义小部件的东西都可以绕过。

这是django/forms/widgets.py的摘录:

class DateInput(TextInput):
    def __init__(self, attrs=None, format=None):
        super(DateInput, self).__init__(attrs)
        if format:
            self.format = format
            self.manual_format = True
        else:
            self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
            self.manual_format = False

您会注意到小部件的格式是使用格式模块设置的。根据语言环境选择格式模块。如果您从美国浏览,Django 将默认选择django.conf.formats.locale.en.formats.py。在这里您将找到默认格式:

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'
)

正如您在第一个代码块中看到的,Django 选择了其中的第一个。更改格式的彻底方法是创建您自己的格式模块,覆盖 Django 对相关语言环境的默认设置。为此,请查看FORMAT_MODULE_PATH。如果您要做的只是覆盖默认日期格式,我会说节省一些时间和猴子补丁。我将此添加到我的设置文件中,一切似乎都以我喜欢的默认格式运行良好:

DATE_INPUT_FORMATS = ('%m/%d/%Y', '%m/%d/%y', '%Y-%m-%d',
                      '%b %d %Y', '%b %d, %Y', '%d %b %Y',
                      '%d %b, %Y', '%B %d %Y', '%B %d, %Y',
                      '%d %B %Y', '%d %B, %Y')
from django.conf.locale.en import formats
formats.DATE_INPUT_FORMATS = DATE_INPUT_FORMATS

【讨论】:

【参考方案4】:

在我使用的表单中:

def today():
    from datetime import date
    return date.today().strftime("%d.%m.%Y")

when = models.DateField(u'Когда', default=today)

【讨论】:

以上是关于使 Django forms.DateField 显示使用本地日期格式的主要内容,如果未能解决你的问题,请参考以下文章

Django/Python 在 DateTimeField 上设置最小/最大日期值

如何在 django 中使用 Datepicker

如何将 Django 日期格式更改为 dd/mm/yy?

我正在尝试使用模型表单小部件更新模型。除了 forms.DateField 之外的所有字段都可以在 HTML 表单中进行编辑

如何从表单中的验证中排除少数字段

设置日期/时间输入字段的默认视图,覆盖用户区域设置?