Создание форм Django. DateField показывает использование локального формата даты.
Вопрос
Я пытаюсь найти простой способ создания форм, отображающих даты в австралийском формате (дд/мм/гггг).Это был единственный способ, которым я смог это сделать.Кажется, должно быть лучшее решение.
Что следует отметить:
- Создан новый виджет, который отображает значение даты в формате дд/мм/гггг.
- Создано новое поле даты для добавления строки формата даты поиска к списку значений, которые оно пытается использовать.
Я предполагаю, что идеальным решением было бы поле даты, которое автоматически локализовалось, но у меня это не сработало (strftime, похоже, не поддерживает Юникод, но я не очень старался)
Я что-то пропустил?Есть ли более элегантное решение?Это надежный подход?
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()
Решение
Конечно, я не джедай Джанго/Питон, но...
Я не думаю, что в вашем подходе есть что-то неправильное.Это чистое чтение.
Возможно, вам не понадобится создавать собственный виджет только для отображения даты в правильном формате при первом отображении формы.Просто используйте 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
class, но может ввести - если вы хотите, чтобы каждый класс формы вызывал 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
вы перезаписываете поле формы, возвращаемое custom_fields, и, следовательно, полностью теряете настройку.
Я думаю, ваш подход более читаем.
Другие советы
Раньше я использовал этот простой подход:просто установите атрибут «формат» DateField.widget в начале формы:
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 для рассматриваемой локали.Для этого загляните 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
В своей форме я использую:
def today():
from datetime import date
return date.today().strftime("%d.%m.%Y")
when = models.DateField(u'Когда', default=today)