Django Import-Export DateTime 天真的日期时间错误

Django Import-Export DateTime Naive DateTime Error

导入日期时间错误消息:

 RuntimeWarning: DateTimeField Entry.date received a naive datetime (2020-07-20 09:23:19.881763) while time zone support is active.
  RuntimeWarning)

用户是否可以 select 他们所在的日期时间或至少导入添加了 +00 的数据?目前,我似乎无法在添加日期时间字段后导入。

现在我正在尝试这个issue solution

resources.py

class TzDateTimeWidget(DateTimeWidget):

    def render(self, value, obj=None):
        if settings.USE_TZ:
            value = localtime(value)
        return super(TzDateTimeWidget, self).render(value)

class EntryResource(resources.ModelResource):
    date = fields.Field(
        column_name='date',
        attribute='datetime',
        widget=TzDateTimeWidget(format='"%Y-%m-%d %H:%M:%S"'))


    class Meta:
        model = Entry
        fields = ('date', 'entry_type', 'amount', 'price', 'fee', 'reg_fee', 'id',)
        import_order = fields
        skip_unchanged = False
        report_skipped = True

csv 文件

2020-07-17 7:42:39,,40,14.56,0,Entry,0
2020-07-17 7:47:16,,40,14.78,0,Entry,0

问题出在你的对象上。以下是正确的日期时间对象的外观:

>>> from django.utils import timezone
>>> import pytz
>>> timezone.now()
datetime.datetime(2013, 11, 20, 20, 8, 7, 127325, tzinfo=pytz.UTC)

这是一个天真的对象:

>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2013, 11, 20, 20, 9, 26, 423063)

我假设错误是在您尝试直接转换 csv 文件时发生的。你应该做什么来分离值,将它们分配给变量,然后将它们一个一个地添加到一个日期时间对象中。

Research

问题是您的 csv 文件中的日期时间不是 Timezone aware。有几种方法可以解决这个问题。

选项 1 - 所有用户都在一个时区

如果您知道提供的日期始终在您的时区内,则不需要 csv 中的时区信息,因为它将 converted during import 并且具有正确的时区。

选项 2 - CSV 包含 TZ 感知时间戳

如果提供的时间戳是时区感知的,那么您可以在导入期间处理此问题:

csv:

2020-07-20 00:00:00+03:00,40,14.56,0,Entry,0

小部件:

class TzDateTimeWidget(widgets.DateTimeWidget):
    def clean(self, value, row=None, *args, **kwargs):
        if not value:
            return None
        if isinstance(value, datetime):
            return value
        for format in self.formats:
            try:
                if settings.USE_TZ:
                    dt = parse_datetime(value)
                return dt
            except (ValueError, TypeError):
                continue
        raise ValueError("Enter a valid date/time.")

选项 3 - 为每个用户存储时区并在导入期间应用它

如果您的用户可以在任何时区,但不可能在 csv 中对 tz 进行编码,那么您可以存储用户的时区(例如,在自定义用户模型实例中),并为用户应用转换导入期间。

这个的简化版本是:

class UserDateTimeWidget(widgets.DateTimeWidget):
    def __init__(self, user_tz_dict):
        """pass in a dict mapping user_id to timezone"""
        super().__init__()
        self.user_dict = user_tz_dict

    def clean(self, value, row=None, *args, **kwargs):
        dt = super().clean(value, row, args, kwargs)
        # the row will need to contain a reference to the user id
        user_id = row.get("user_id")
        user_tz = self.user_dict.get(user_id)
        return make_aware(dt, timezone=user_tz)

重要的是要注意,这依赖于 csv 时间戳采用一致的标准,例如 UTC。

请注意,还有其他方法可以实现上述目标,例如重写模型 save() 方法以在保存实例时应用用户的时区。显然你必须 link 用户到导入的对象。

附带说明一下,您引用的 TzDateTimeWidget 只会在导出数据时以定义的时区格式化日期。此功能已存在于 DateTimeWidget.

如果您使用 django-import-export 导出数据并且日期时间不是导出时区感知的,那么只需在设置中更改日期时间输入格式:

DATETIME_INPUT_FORMATS = ("%Y-%m-%dT%H:%M:%S%Z",)