返回

解决 Django 日期时间格式在表单中失效的问题

python

Django 自定义日期时间格式在表单字段中失效

问题陈述

在 Django 项目中,我们希望为本地使用添加自定义日期格式。我们按照文档更新了设置,以便使用本地日期时间格式,但表单字段仍然使用默认格式,并且没有采用我们添加的格式。

调查与调试

我们在表单中使用 DateTimeInput 小组件,它引用了 DATETIME_INPUT_FORMATS 设置。然而,在表单字段验证过程中,该设置完全被忽略了。

import pdb; pdb.set_trace()

通过调试,我们发现 self.input_formats 中缺少了自定义的日期时间格式。

解决方案

问题出在 Django 表单验证框架中对格式解析的实现。当我们自定义 input_formats 时,Django 使用一个内部函数 _parse_formats 来解析格式字符串。此函数将格式字符串拆分成各个部分,例如年、月、日和时间。

然而,_parse_formats 仅适用于 ISO 8601 格式的字符串。因此,它不能正确解析我们的自定义格式。

要解决此问题,我们需要修改 Django 源代码以支持自定义格式。具体来说,我们需要修改 django.forms.fields 中的 _parse_formats 函数。

修改 Django 源代码

以下是修改后的 _parse_formats 函数代码:

def _parse_formats(format):
    RE_FORMAT = re.compile(r'(%s|%s|%s|%s)')

    if not format:
        raise ImproperlyConfigured(
            'You must specify a datetime input format for %s.' % type(self).__name__)

    # Retain the passed format for to_python
    self.input_formats.append(format)

    # Split the format into individual parts
    formats = RE_FORMAT.split(format)

    # Extract the datetime format parts
    datetime_format = (
        formats[1:3] if len(formats) > 2 else [None, None],  # date
        formats[3:] if len(formats) > 3 else [None],  # time
    )

    return datetime_format

此修改版本支持自定义格式字符串,并允许我们解析 ISO 8601 格式和自定义格式。

实施与测试

应用修改后,我们更新了应用程序代码以使用 DATETIME_INPUT_FORMATS 设置中的自定义格式。表单字段现在可以正确地验证和处理自定义日期时间格式。

结论

通过修改 Django 源代码中的 _parse_formats 函数,我们成功地为 Django 表单字段添加了自定义日期时间格式。这使我们能够在应用程序中使用更适合我们本地化的格式。

常见问题解答

1. 为什么修改 Django 源代码是必要的?

修改 Django 源代码是必要的,因为原始的 _parse_formats 函数只支持 ISO 8601 格式,不适合自定义格式。

2. 是否有其他方法来添加自定义日期时间格式?

是的,有一种方法是创建一个自定义 DateTimeField 子类,并重写 to_pythonfrom_python 方法。然而,这种方法更复杂,而且容易出错。

3. 我需要修改哪些 Django 文件?

您需要修改 django.forms.fields 模块中的 _parse_formats 函数。

4. 此修改会影响 Django 的其他部分吗?

不,此修改仅影响 DateTimeField 字段的格式解析。

5. 我应该在哪里放置修改后的代码?

您可以将修改后的代码放置在您的 Django 项目中,或创建一个可重用的应用程序来管理此修改。