更改 DatePicker 的格式导致验证错误

Changing Format Of DatePicker Causes Validation Errors

我正在使用日期时间选择器,用户可以在其中选择月份 (MonthPickerInput)。

models.py

birthdayMonth = models.DateField(null=True, default=now)

forms.py

from bootstrap_datepicker_plus import MonthPickerInput

class QuestionForm(forms.ModelForm):

    widgets = {
        'birthdayMonth': MonthPickerInput(
            options={
                "showClose": False,
                "showClear": False,
                "showTodayButton": False,
            }
        ),
    }

用户单击表单字段,日历下拉,他们 select 一个月和一年。 MonthPicker 自动将日期设置为“1”。这在后端很好,但在用户填写的表单的前端,它显示为 2020-03-01。相反,我希望它像这样显示 March 2020(03-2020 也可以)。为此,我在 froms.py:

中向 format 添加了一个字段
widgets = {
    'birthdayMonth': MonthPickerInput(
        options={
            "format":"MMMM, YYYY",
        }
    ),
}

这在前端正确显示,但是表单验证总是失败(每当我提交表单时,日历输入突出显示为红色但没有错误消息)。

我在我的 views.py 中打印了 POST 数据,然后点击 if form.is_valid() 和添加 format 到它打印的小部件 2020-08-01,而添加 "format":"MMMM, YYYY" 后,它会打印 08-2020。我猜这是导致问题的原因。

如何才能只更改前端显示,而将后端保留为原始格式,这样我的验证就不会出错了?我想我需要使用 JQuery 但所有尝试都失败了:

// this does nothing
$('#birthdayMonth').datepicker({
    format: 'MMMM/YYYY',
});

// I have tried many more things with JQuery but they do nothing or cause my code to go buggy (such as displaying two calendars on top of each other

我想做的另一件事是从我的 POST 数据中获取 birthdayMonth 并在将其传递给我的 clean 方法之前添加日期字段。虽然我确信这会奏效,但它非常骇人听闻,肯定会有更好的方法。

--编辑-- 如果我添加

birthdayMonth = forms.DateField(
    input_formats=['MMMM, YYYY'],
    widget=MonthPickerInput(format='MMMM, YYYY')
)

正如 Ben 所建议的那样,它将 December, 2020 传递给了我的视图,这就是验证失败的原因。

谢谢。

我的建议是让你的后端保持原样,你可以在你的模板中进行必要的格式化,例如:

{{birthdayMonth|date:"F Y"}}

F 会给出完整的月份,Y 会给出完整的年份。

更多细节和其他格式,可以参考文档:https://docs.djangoproject.com/en/3.0/ref/templates/builtins/

https://django-bootstrap-datepicker-plus.readthedocs.io/en/latest/Usage.html?highlight=MonthPickerInput#customize-datepicker-format

“为了使用任意格式,您必须为字段的 input_formats 和小部件的格式指定模式。”

 class BirthdayForm(forms.Form):
     birthdayMonth = forms.DateField(
         input_formats=['MMMM, YYYY'],
         widget=MonthPickerInput(format='MMMM, YYYY')
     )

否则,在干净的方法中添加“day”字段没有什么坏处:

https://docs.djangoproject.com/en/3.0/ref/forms/validation/#cleaning-a-specific-field-attribute

 class BirthdayForm(forms.Form):
    # ...

    def clean_birthdayMonth(self):
        date_ = self.cleaned_data['birthdayMonth']
        date_ = date_.replace(day=1)

        return date_

如果您可以从表单中获取“08-2020”或“2020 年 8 月”,则可以在 clean 方法中轻松转换为 python 日期时间

 class BirthdayForm(forms.Form):
    # ...

    def clean_birthdayMonth(self):
        import datetime

        dt_str = '08-2020'
        dt_obj = datetime.datetime.strptime(dt_str, '%m-%Y')
        
        dt_str = "August, 2020"
        dt_obj = datetime.datetime.strptime(dt_str, '%B, %Y')


        dt_str = self.cleaned_data['birthdayMonth']
        dt_obj = datetime.datetime.strptime(dt_str, '%B, %Y')

        return dt_obj

听起来好像是在 form.is_valid() 为 运行 之前捕获数据。 https://docs.djangoproject.com/en/dev/ref/request-response/#querydict-objects

post = request.POST.copy() # To get a mutable version

dt_str = post['birthdayMonth']  # "August, 2020"
dt_obj = datetime.datetime.strptime(dt_str, '%B, %Y')

post['birthdayMonth'] = dt_obj

# don't forget to update original POST
request.POST = post

在settings.py设置需要的时间格式

DATE_INPUT_FORMATS = ['%d/%m/%Y']

并制作

USE_L10N = False

forms.py导入设置

from django.conf import settings

然后加入class form_name()

birth_date = forms.DateField(widget=forms.DateInput,input_formats= settings.DATE_INPUT_FORMATS)