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",)
导入日期时间错误消息:
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",)