使 Django forms.DateField 显示使用本地日期格式
题
我正在尝试找到一种简单的方法来构建以澳大利亚格式(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()
解决方案
当然,我不是 django/python Jedi,但是......
我不认为你的做法有什么问题。这是一本干净的读物。
您可能不需要创建自己的小部件,只是为了在第一个表单显示上以正确的格式呈现日期。只需使用 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
(参见 接受的答案 对于这个遥远相关的问题),意思是:
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返回的表单字段,因此完全失去了自定义。
我认为你的方法更具可读性。
其他提示
我以前使用过这种简单的方法:只需在表单的 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']
所有自定义小部件的内容都可以被绕过。
这是摘录自 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 对于相关区域设置的默认设置。为此,请查看 格式模块路径. 。如果您想做的只是覆盖默认日期格式,我建议您节省一些时间和猴子补丁。我将其添加到我的设置文件中,一切似乎都以我喜欢的默认格式运行得很好:
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
在我的表格中,我使用:
def today():
from datetime import date
return date.today().strftime("%d.%m.%Y")
when = models.DateField(u'Когда', default=today)